From b12b55a5ee1b34b5a3f9d21533fa9fc909207285 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期四, 05 二月 2026 09:40:13 +0800
Subject: [PATCH] Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New

---
 src/views/reportAnalysis/qualityAnalysis/components/center-center.vue |  355 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 355 insertions(+), 0 deletions(-)

diff --git a/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue b/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue
new file mode 100644
index 0000000..8d28f7a
--- /dev/null
+++ b/src/views/reportAnalysis/qualityAnalysis/components/center-center.vue
@@ -0,0 +1,355 @@
+<template>
+  <div>
+    <div class="warn-panel">
+      <div class="warn-header">
+        <div class="warn-header-left">
+          <div class="warn-badge"></div>
+          <span class="warn-title">涓嶅悎鏍奸璀�</span>
+        </div>
+        <div class="warn-range" @click="handleRangeClick">杩�7澶�</div>
+      </div>
+
+      <div class="warn-body">
+        <div class="warn-list" role="list">
+          <div v-for="item in warnings" :key="item.id" class="warn-item" role="listitem" @click="openWarning(item)">
+            <div class="warn-tag" :class="tagClass(item.type)">{{ item.parentProductTitle }}-{{ item.productTitle }}
+            </div>
+            <div class="warn-text" :title="item.title">{{ item.title }}</div>
+            <div class="warn-action" @click.stop="openWarning(item)">鏌ョ湅</div>
+            <div class="warn-date">{{ item.date }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { computed, getCurrentInstance, ref, onMounted } from 'vue'
+import Echarts from '@/components/Echarts/echarts.vue'
+import { nonComplianceWarning } from '@/api/viewIndex.js'
+
+const { proxy } = getCurrentInstance() || {}
+
+const warnings = ref([])
+
+// 鍗犳瘮鏁版嵁
+const ratios = ref({
+  rawMaterialRatio: 0,
+  semiFinishedProductRatio: 0,
+  finishedProductRatio: 0,
+})
+
+const TAG_COLORS = {
+  raw: '#7C4DFF',
+  final: '#F5A000',
+  semi: '#FF66CC',
+}
+
+const tagClass = (type) => {
+  if (type === 'raw') return 'tag-raw'
+  if (type === 'final') return 'tag-final'
+  return 'tag-semi'
+}
+
+// 鏍规嵁productTitle鏄犲皠绫诲瀷
+const mapProductTitleToType = (productTitle) => {
+  if (productTitle === '鍘熸潗鏂�') return 'raw'
+  if (productTitle === '鍗婃垚鍝�') return 'semi'
+  if (productTitle === '鎴愬搧') return 'final'
+  return 'raw' // 榛樿鍊�
+}
+
+const pieChartStyle = { width: '100%', height: '100%' }
+
+const pieOptions = {
+  backgroundColor: 'transparent',
+  textStyle: { color: '#B8C8E0' },
+}
+
+const pieTooltip = {
+  trigger: 'item',
+  formatter: (p) => `${p.name}锛�${p.value}%`,
+}
+
+const pieData = computed(() => {
+  return [
+    { name: '鍘熸潗鏂�', value: ratios.value.rawMaterialRatio, itemStyle: { color: TAG_COLORS.raw } },
+    { name: '鍗婃垚鍝�', value: ratios.value.semiFinishedProductRatio, itemStyle: { color: TAG_COLORS.semi } },
+    { name: '鎴愬搧', value: ratios.value.finishedProductRatio, itemStyle: { color: TAG_COLORS.final } },
+  ]
+})
+
+const pieSeries = computed(() => {
+  return [
+    {
+      type: 'pie',
+      radius: ['0%', '68%'],
+      center: ['50%', '50%'],
+      startAngle: 90,
+      clockwise: true,
+      avoidLabelOverlap: true,
+      label: { show: false },
+      labelLine: { show: false },
+      itemStyle: {
+        borderColor: '#071a3a',
+        borderWidth: 4,
+        shadowBlur: 14,
+        shadowColor: 'rgba(0, 0, 0, 0.35)',
+      },
+      data: pieData.value,
+    },
+    {
+      // 鍐呭湀鏆楃幆锛屽寮哄眰娆�
+      type: 'pie',
+      radius: ['70%', '74%'],
+      center: ['50%', '50%'],
+      silent: true,
+      label: { show: false },
+      labelLine: { show: false },
+      itemStyle: { color: 'rgba(78, 228, 255, 0.12)' },
+      data: [1],
+    },
+  ]
+})
+
+const fetchWarnings = async () => {
+  try {
+    const res = await nonComplianceWarning()
+    if (res?.code === 200 && res?.data) {
+      const data = res.data
+
+      // 鏇存柊鍗犳瘮鏁版嵁
+      ratios.value = {
+        rawMaterialRatio: data.rawMaterialRatio ?? 0,
+        semiFinishedProductRatio: data.semiFinishedProductRatio ?? 0,
+        finishedProductRatio: data.finishedProductRatio ?? 0,
+      }
+
+      // 鏇存柊璀﹀憡鍒楄〃
+      const children = data.children || []
+      warnings.value = children.map((item, idx) => {
+        const type = mapProductTitleToType(item.parentProductTitle)
+        const date = item.date ? item.date.replace(/-/g, '.') : ''
+        return {
+          id: item.id ?? `warning-${idx}`,
+          type,
+          parentProductTitle: item.parentProductTitle || '鍘熸潗鏂�',
+          productTitle: item.productTitle || '鍘熸潗鏂�',
+          title: item.description || '涓嶅悎鏍奸璀�',
+          date,
+        }
+      })
+    }
+  } catch (e) {
+    // 鎺ュ彛澶辫触鍒欎繚鎸佺┖鏁版嵁
+    console.error('鑾峰彇涓嶅悎鏍奸璀﹀け璐�:', e)
+  }
+}
+
+const openWarning = (item) => {
+  const title = `銆�${item.parentProductTitle}-${item.productTitle}銆�${item.title}`
+  if (proxy?.$modal?.alert) {
+    proxy.$modal.alert(title)
+    return
+  }
+  // 鍏滃簳锛氭病鏈夊叏灞� modal 鏃剁敤 console
+  console.log('warning:', { ...item })
+}
+
+const handleRangeClick = () => {
+  // 鍏堟寜鎴浘鍋氶潤鎬佲�滆繎7澶┾�濓紝鍚庣画鏈夌湡瀹炵瓫閫夐渶姹傚啀鎺ュ叆
+}
+
+onMounted(() => {
+  fetchWarnings()
+})
+</script>
+
+<style scoped>
+.warn-panel {
+  border: 1px solid #1a58b0;
+  padding: 0 18px 18px;
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  height: 100%;
+  box-sizing: border-box;
+}
+
+.warn-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  border-bottom: 1px solid;
+  border-image: linear-gradient(270deg,
+      rgba(0, 126, 255, 0) 0%,
+      rgba(0, 126, 255, 0.4549) 35%,
+      #007eff 78%,
+      #007eff 100%) 1;
+  padding: 10px 0 6px;
+}
+
+.warn-header-left {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.warn-badge {
+  width: 18px;
+  height: 18px;
+  background: linear-gradient(180deg, #2aa8ff 0%, #4ee4ff 100%);
+  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
+  box-shadow: 0 0 12px rgba(78, 228, 255, 0.25);
+}
+
+.warn-title {
+  font-weight: 600;
+  font-size: 18px;
+  background: linear-gradient(360deg, #056dff 0%, #43e8fc 100%);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+  background-clip: text;
+  line-height: 24px;
+}
+
+.warn-range {
+  height: 32px;
+  padding: 0 14px;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 4px;
+  color: #ffffff;
+  font-weight: 600;
+  background: linear-gradient(180deg, rgba(51, 120, 255, 1) 0%, rgba(0, 164, 237, 1) 100%);
+  border: 1px solid rgba(78, 228, 255, 0.25);
+  cursor: pointer;
+}
+
+.warn-body {
+  display: grid;
+  gap: 18px;
+  align-items: stretch;
+  min-height: 260px;
+}
+
+.warn-list {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  padding-top: 6px;
+}
+
+.warn-item {
+  display: grid;
+  grid-template-columns: 130px 1fr auto 110px;
+  align-items: center;
+  gap: 12px;
+  color: #b8c8e0;
+  font-size: 14px;
+  line-height: 1.2;
+  padding: 8px 0;
+  border-radius: 4px;
+  transition: background-color 0.2s, color 0.2s;
+}
+
+.warn-item:hover {
+  color: #ff4d4f;
+  background-color: rgba(255, 77, 79, 0.06);
+}
+
+.warn-item:hover .warn-text {
+  color: #ff4d4f;
+}
+
+.warn-tag {
+  height: 28px;
+  padding: 0 10px;
+  border-radius: 4px;
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  font-weight: 700;
+  color: #ffffff;
+}
+
+.tag-raw {
+  background: #7c4dff;
+}
+
+.tag-final {
+  background: #f5a000;
+}
+
+.tag-semi {
+  background: #ff66cc;
+}
+
+.warn-text {
+  color: #e8f1ff;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.warn-action {
+  color: #ff4d4f;
+  font-weight: 700;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.warn-date {
+  color: rgba(184, 200, 224, 0.75);
+  white-space: nowrap;
+}
+
+.warn-chart {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.chart-frame {
+  width: 100%;
+  height: 260px;
+  border: 2px dashed rgba(184, 200, 224, 0.35);
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: radial-gradient(circle at 50% 50%, rgba(78, 228, 255, 0.08) 0%, rgba(0, 0, 0, 0) 65%);
+}
+
+/* 澶栧湀鍒诲害鐜� */
+.chart-frame::before {
+  content: '';
+  position: absolute;
+  width: 220px;
+  height: 220px;
+  border-radius: 50%;
+  background: repeating-conic-gradient(from 0deg, rgba(78, 228, 255, 0.75) 0 1deg, rgba(78, 228, 255, 0) 1deg 9deg);
+  -webkit-mask: radial-gradient(circle, transparent 62%, #000 63%);
+  mask: radial-gradient(circle, transparent 62%, #000 63%);
+  opacity: 0.5;
+  pointer-events: none;
+}
+
+/* 鍗佸瓧杈呭姪绾� */
+.chart-frame::after {
+  content: '';
+  position: absolute;
+  width: 240px;
+  height: 240px;
+  background:
+    linear-gradient(to right, rgba(78, 228, 255, 0) 0%, rgba(78, 228, 255, 0.55) 50%, rgba(78, 228, 255, 0) 100%),
+    linear-gradient(to bottom, rgba(78, 228, 255, 0) 0%, rgba(78, 228, 255, 0.55) 50%, rgba(78, 228, 255, 0) 100%);
+  background-size: 100% 1px, 1px 100%;
+  background-position: center, center;
+  background-repeat: no-repeat;
+  opacity: 0.35;
+  pointer-events: none;
+}
+</style>

--
Gitblit v1.9.3