| | |
| | | <template> |
| | | <div> |
| | | <div class="panel-root"> |
| | | <div class="warn-panel"> |
| | | <div class="warn-header"> |
| | | <div class="warn-header-left"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, getCurrentInstance, ref, onMounted } from 'vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import { getCurrentInstance, ref, onMounted } from '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' |
| | |
| | | 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 || [] |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .panel-root { |
| | | flex: 1; |
| | | min-height: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .warn-panel { |
| | | border: 1px solid #1a58b0; |
| | | border: 1px solid var(--bi-panel-border); |
| | | background: var(--bi-panel-bg); |
| | | border-radius: 8px; |
| | | padding: 0 18px 18px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | height: 100%; |
| | | flex: 1; |
| | | min-height: 0; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .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; |
| | | border-bottom: 1px solid rgba(143, 163, 200, 0.15); |
| | | padding: 10px 0 6px; |
| | | } |
| | | |
| | |
| | | gap: 10px; |
| | | } |
| | | |
| | | /* 品牌蓝细竖条,与 PanelHeader 呼应 */ |
| | | .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); |
| | | width: 3px; |
| | | height: 14px; |
| | | border-radius: 2px; |
| | | background: linear-gradient(180deg, var(--bi-accent-bright) 0%, var(--bi-accent) 100%); |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .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; |
| | | font-weight: 500; |
| | | font-size: 16px; |
| | | color: var(--bi-text-strong); |
| | | letter-spacing: 1px; |
| | | line-height: 24px; |
| | | } |
| | | |
| | | .warn-range { |
| | | height: 32px; |
| | | padding: 0 14px; |
| | | height: 28px; |
| | | padding: 0 12px; |
| | | 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); |
| | | border-radius: 6px; |
| | | color: var(--bi-text-strong); |
| | | font-weight: 500; |
| | | font-size: 13px; |
| | | background: rgba(74, 108, 240, 0.15); |
| | | border: 1px solid rgba(74, 108, 240, 0.35); |
| | | cursor: pointer; |
| | | transition: border-color 0.2s ease; |
| | | } |
| | | |
| | | .warn-range:hover { |
| | | border-color: var(--bi-accent-bright); |
| | | } |
| | | |
| | | .warn-body { |
| | | display: grid; |
| | | gap: 18px; |
| | | align-items: stretch; |
| | | min-height: 260px; |
| | | flex: 1; |
| | | min-height: 0; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .warn-list { |
| | |
| | | grid-template-columns: 130px 1fr auto 110px; |
| | | align-items: center; |
| | | gap: 12px; |
| | | color: #b8c8e0; |
| | | color: var(--bi-text); |
| | | font-size: 14px; |
| | | line-height: 1.2; |
| | | padding: 8px 0; |
| | |
| | | } |
| | | |
| | | .warn-item:hover { |
| | | color: #ff4d4f; |
| | | background-color: rgba(255, 77, 79, 0.06); |
| | | color: var(--bi-down); |
| | | background-color: rgba(255, 107, 107, 0.06); |
| | | } |
| | | |
| | | .warn-item:hover .warn-text { |
| | | color: #ff4d4f; |
| | | color: var(--bi-down); |
| | | } |
| | | |
| | | .warn-tag { |
| | | height: 28px; |
| | | height: 24px; |
| | | padding: 0 10px; |
| | | border-radius: 4px; |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-weight: 700; |
| | | font-weight: 500; |
| | | font-size: 12px; |
| | | color: #ffffff; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 序列色区分检测环节,与大屏图表配色一致 */ |
| | | .tag-raw { |
| | | background: #7c4dff; |
| | | background: var(--bi-accent-bright); |
| | | } |
| | | |
| | | .tag-final { |
| | | background: #f5a000; |
| | | background: #8E7CE6; |
| | | } |
| | | |
| | | .tag-semi { |
| | | background: #ff66cc; |
| | | background: #35C6D6; |
| | | } |
| | | |
| | | .warn-text { |
| | | color: #e8f1ff; |
| | | color: var(--bi-text-strong); |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .warn-action { |
| | | color: #ff4d4f; |
| | | font-weight: 700; |
| | | color: var(--bi-down); |
| | | font-weight: 600; |
| | | white-space: nowrap; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .warn-date { |
| | | color: rgba(184, 200, 224, 0.75); |
| | | color: var(--bi-text); |
| | | 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; |
| | | font-variant-numeric: tabular-nums; |
| | | } |
| | | </style> |