ccy_DIB/pages/DigitalIntelligenceDashboard/components/InventoryAccuracyAnalysis.vue
ylj20011123 c78652a8d1 update
2025-10-23 18:35:54 +08:00

773 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="inventory-accuracy-analysis">
<view class="report-header">
<text class="report-title">库存精准度分析</text>
<view class="report-period">
<text class="period-label">分析周期</text>
<text class="period-value">{{ analysisPeriod }}</text>
</view>
</view>
<!-- 关键指标卡片 -->
<view class="metrics-row">
<view class="metric-card">
<view class="metric-icon accuracy"></view>
<text class="metric-title">盘点准确率</text>
<view class="metric-value-container">
<text class="metric-value">{{ accuracyRate }}%</text>
<text class="metric-unit">优秀</text>
</view>
</view>
<view class="metric-card">
<view class="metric-icon difference"></view>
<text class="metric-title">平均差异率</text>
<view class="metric-value-container">
<text class="metric-value">{{ avgDifference }}%</text>
<text class="metric-unit">较低</text>
</view>
</view>
<view class="metric-card">
<view class="metric-icon variance"></view>
<text class="metric-title">差异金额</text>
<view class="metric-value-container">
<text class="metric-value">¥{{ formatMoney(varianceAmount) }}</text>
<text class="metric-unit">万元</text>
</view>
</view>
</view>
<!-- 盘点差异比例分布饼图 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">盘点差异比例分布</text>
<text class="chart-subtitle">按差异程度分类统计</text>
</view>
<view class="chart-content">
<view class="pie-chart-container">
<QiunDataCharts
type="pie"
:opts="pieChartOpts"
:chartData="pieChartData"
:canvas2d="true"
:inScrollView="true"
canvasId="variancePieChart"
/>
<view class="pie-legend">
<view class="legend-item" v-for="(item, index) in varianceData" :key="index">
<view class="legend-color" :style="{ backgroundColor: item.color }"></view>
<text class="legend-name">{{ item.name }}</text>
<text class="legend-value">{{ item.percentage }}%</text>
</view>
</view>
</view>
</view>
</view>
<!-- 差异趋势分析折线图 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">盘点差异趋势分析</text>
<text class="chart-subtitle">最近6个月盘点准确率变化趋势</text>
</view>
<view class="chart-content">
<view class="line-chart-container">
<QiunDataCharts
type="line"
:opts="lineChartOpts"
:chartData="lineChartData"
:canvas2d="true"
:inScrollView="true"
canvasId="varianceTrendChart"
/>
<view class="chart-legend">
<view class="legend-item">
<view class="legend-dot accuracy"></view>
<text class="legend-text">盘点准确率</text>
</view>
<view class="legend-item">
<view class="legend-dot variance"></view>
<text class="legend-text">平均差异率</text>
</view>
</view>
</view>
</view>
</view>
<!-- 各类别差异对比柱状图 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">各类别盘点差异对比</text>
<text class="chart-subtitle">不同商品类别的盘点差异分析</text>
</view>
<view class="chart-content">
<view class="bar-chart-container">
<QiunDataCharts
type="column"
:opts="barChartOpts"
:chartData="barChartData"
:canvas2d="true"
:inScrollView="true"
canvasId="categoryVarianceChart"
/>
</view>
</view>
</view>
<!-- 重点差异商品列表 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">重点差异商品清单</text>
<text class="chart-subtitle">差异率较高的商品需要重点关注</text>
</view>
<view class="variance-list">
<view class="variance-item" v-for="(item, index) in highVarianceList" :key="index" :class="[getVarianceLevel(item.varianceRate)]">
<view class="variance-rank">{{ index + 1 }}</view>
<view class="variance-content">
<text class="product-name">{{ item.name }}</text>
<text class="product-category">{{ item.category }}</text>
</view>
<view class="variance-data">
<view class="variance-info">
<text class="variance-label">系统数量</text>
<text class="variance-value">{{ item.systemQty }}</text>
</view>
<view class="variance-info">
<text class="variance-label">实际数量</text>
<text class="variance-value">{{ item.actualQty }}</text>
</view>
</view>
<view class="variance-percentage">
<text class="variance-rate" :class="{ 'negative': item.varianceRate < 0 }">
{{ item.varianceRate > 0 ? '+' : '' }}{{ item.varianceRate }}%
</text>
<text class="variance-amount">¥{{ formatMoney(item.varianceAmount) }}</text>
</view>
</view>
</view>
</view>
<!-- 改进建议 -->
<view class="chart-card">
<view class="chart-header">
<text class="chart-title">改进建议</text>
</view>
<view class="suggestions">
<view class="suggestion-item" v-for="(item, index) in suggestions" :key="index">
<view class="suggestion-icon">{{ item.icon }}</view>
<view class="suggestion-content">
<text class="suggestion-title">{{ item.title }}</text>
<text class="suggestion-desc">{{ item.description }}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import QiunDataCharts from './qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue'
export default {
components: {
QiunDataCharts
},
data() {
return {
analysisPeriod: '2024年10月',
accuracyRate: 96.8,
avgDifference: 3.2,
varianceAmount: 12.45,
// 差异分布数据
varianceData: [
{ name: '无差异', value: 424856, percentage: 87.5, color: '#52C41A' },
{ name: '轻微差异(±5%)', value: 45678, percentage: 9.4, color: '#1890FF' },
{ name: '中等差异(±10%)', value: 12345, percentage: 2.5, color: '#FAAD14' },
{ name: '严重差异(±20%)', value: 1567, percentage: 0.4, color: '#FF7A45' },
{ name: '重大差异(>±20%)', value: 432, percentage: 0.2, color: '#FF4D4F' }
],
// 差异趋势数据
varianceTrendData: {
categories: ['5月', '6月', '7月', '8月', '9月', '10月'],
accuracyData: [94.2, 95.1, 94.8, 95.7, 96.2, 96.8],
avgVarianceData: [5.8, 4.9, 5.2, 4.3, 3.8, 3.2]
},
// 各类别差异数据
categoryVarianceData: [
{ category: '保健品', varianceRate: 2.8, count: 156234 },
{ category: '茶叶', varianceRate: 3.2, count: 128456 },
{ category: '食品', varianceRate: 4.1, count: 98567 },
{ category: '饮品', varianceRate: 2.5, count: 56789 },
{ category: '工艺品', varianceRate: 6.7, count: 23456 },
{ category: '纺织品', varianceRate: 3.9, count: 12345 },
{ category: '化妆品', varianceRate: 5.2, count: 8765 },
{ category: '其他', varianceRate: 7.8, count: 560 }
],
// 高差异商品列表
highVarianceList: [
{ name: '银手镯', category: '工艺品', systemQty: 156, actualQty: 134, varianceRate: -14.1, varianceAmount: 3.45 },
{ name: '云南红酒', category: '饮品', systemQty: 234, actualQty: 267, varianceRate: 14.1, varianceAmount: 2.78 },
{ name: '普洱茶砖', category: '茶叶', systemQty: 189, actualQty: 165, varianceRate: -12.7, varianceAmount: 1.89 },
{ name: '玉石吊坠', category: '工艺品', systemQty: 78, actualQty: 89, varianceRate: 14.1, varianceAmount: 2.34 },
{ name: '鲜花精油', category: '化妆品', systemQty: 456, actualQty: 398, varianceRate: -12.7, varianceAmount: 1.56 },
{ name: '手工刺绣', category: '纺织品', systemQty: 67, actualQty: 78, varianceRate: 16.4, varianceAmount: 1.23 },
{ name: '三七粉', category: '保健品', systemQty: 234, actualQty: 256, varianceRate: 9.4, varianceAmount: 0.98 },
{ name: '民族服装', category: '纺织品', systemQty: 89, actualQty: 78, varianceRate: -12.4, varianceAmount: 0.87 }
],
// 改进建议
suggestions: [
{
icon: '📊',
title: '完善盘点制度',
description: '建议采用ABC分类法对高价值商品进行更频繁的盘点提高整体准确率'
},
{
icon: '💻',
title: '优化系统管理',
description: '加强库存系统的数据同步机制,确保系统数据与实际库存的一致性'
},
{
icon: '👥',
title: '加强人员培训',
description: '定期对仓库管理人员进行培训,提高盘点操作规范性和数据记录准确性'
},
{
icon: '🔍',
title: '建立差异分析机制',
description: '对重大差异商品进行重点分析,找出差异原因并制定改进措施'
}
]
}
},
computed: {
// 饼图数据
pieChartData() {
return {
series: [{
data: this.varianceData.map(item => ({
name: item.name,
value: item.value
}))
}]
}
},
// 饼图配置
pieChartOpts() {
return {
color: this.varianceData.map(item => item.color),
padding: [5, 5, 5, 5],
dataLabel: true,
legend: {
show: false
},
extra: {
pie: {
activeOpacity: 0.5,
activeRadius: 10,
offsetAngle: 0,
labelWidth: 15,
border: false,
borderWidth: 3,
borderColor: '#FFFFFF'
}
}
}
},
// 折线图数据
lineChartData() {
return {
categories: this.varianceTrendData.categories,
series: [
{
name: '盘点准确率',
data: this.varianceTrendData.accuracyData
},
{
name: '平均差异率',
data: this.varianceTrendData.avgVarianceData
}
]
}
},
// 折线图配置
lineChartOpts() {
return {
color: ['#52C41A', '#FF7A45'],
padding: [15, 15, 15, 15],
dataLabel: false,
legend: {
show: false
},
xAxis: {
disableGrid: true
},
yAxis: {
gridType: 'dash',
dashLength: 2,
data: [
{
min: 0,
max: 100,
title: '%'
},
{
min: 0,
max: 10,
position: 'right',
title: '%'
}
]
},
extra: {
line: {
type: 'curve',
width: 2,
activeType: 'hollow'
}
}
}
},
// 柱状图数据
barChartData() {
return {
categories: this.categoryVarianceData.map(item => item.category),
series: [{
name: '差异率',
data: this.categoryVarianceData.map(item => item.varianceRate)
}]
}
},
// 柱状图配置
barChartOpts() {
return {
color: ['#576EFF'],
padding: [15, 15, 15, 15],
dataLabel: false,
enableScroll: false,
xAxis: {
disableGrid: false,
gridType: 'dash',
rotateLabel: false,
itemCount: 8
},
yAxis: {
gridType: 'dash',
dashLength: 2,
data: [{
min: 0,
title: '差异率(%)'
}]
},
extra: {
column: {
type: 'group',
width: 30,
activeBgColor: '#000000',
activeBgOpacity: 0.08,
linearType: 'custom',
barBorderCircle: true
}
}
}
}
},
methods: {
formatMoney(amount) {
return amount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
},
getVarianceLevel(varianceRate) {
const absRate = Math.abs(varianceRate)
if (absRate >= 20) return 'severe'
if (absRate >= 10) return 'high'
if (absRate >= 5) return 'medium'
return 'low'
}
}
}
</script>
<style scoped lang="less">
@primary-color: #667eea;
@secondary-color: #764ba2;
@success-color: #52c41a;
@warning-color: #faad14;
@error-color: #ff4d4f;
@text-primary: #333;
@text-secondary: #666;
@text-light: #999;
@bg-white: #ffffff;
@border-radius: 16rpx;
@shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
.inventory-accuracy-analysis {
.report-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32rpx;
padding: 0 8rpx;
.report-title {
font-size: 36rpx;
font-weight: 600;
color: @text-primary;
}
.report-period {
display: flex;
align-items: center;
.period-label {
font-size: 24rpx;
color: @text-secondary;
margin-right: 8rpx;
}
.period-value {
font-size: 24rpx;
color: @primary-color;
font-weight: 500;
}
}
}
.metrics-row {
display: flex;
gap: 24rpx;
margin-bottom: 32rpx;
.metric-card {
flex: 1;
background: @bg-white;
border-radius: @border-radius;
padding: 32rpx 24rpx;
box-shadow: @shadow;
text-align: center;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4rpx;
background: linear-gradient(90deg, @primary-color, @secondary-color);
}
.metric-icon {
width: 48rpx;
height: 48rpx;
margin: 0 auto 16rpx;
border-radius: 50%;
position: relative;
&.accuracy {
background: linear-gradient(135deg, #52c41a, #73d13d);
&::after { content: '🎯'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
}
&.difference {
background: linear-gradient(135deg, #1890ff, #40a9ff);
&::after { content: '📏'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
}
&.variance {
background: linear-gradient(135deg, #faad14, #ffc53d);
&::after { content: '💰'; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 24rpx; }
}
}
.metric-title {
font-size: 24rpx;
color: @text-secondary;
margin-bottom: 12rpx;
}
.metric-value-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 4rpx;
}
.metric-value {
font-size: 32rpx;
font-weight: 600;
color: @text-primary;
font-family: 'DINAlternate-Bold', sans-serif;
line-height: 1;
}
.metric-unit {
font-size: 20rpx;
color: @text-light;
line-height: 1;
}
}
}
.chart-card {
background: @bg-white;
border-radius: @border-radius;
padding: 24rpx;
box-shadow: @shadow;
margin-bottom: 24rpx;
.chart-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20rpx;
.chart-title {
font-size: 28rpx;
font-weight: 600;
color: @text-primary;
}
.chart-subtitle {
font-size: 22rpx;
color: @text-light;
margin-top: 4rpx;
}
}
.chart-content {
.pie-chart-container {
display: flex;
flex-direction: column;
align-items: center;
.pie-legend {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 16rpx;
margin-top: 16rpx;
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
.legend-color {
width: 12rpx;
height: 12rpx;
border-radius: 2rpx;
}
.legend-name {
font-size: 22rpx;
color: @text-secondary;
}
.legend-value {
font-size: 22rpx;
color: @text-primary;
font-weight: 600;
}
}
}
}
.line-chart-container {
.chart-legend {
display: flex;
justify-content: center;
gap: 32rpx;
margin-top: 16rpx;
.legend-item {
display: flex;
align-items: center;
gap: 8rpx;
.legend-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
&.accuracy {
background: #52C41A;
}
&.variance {
background: #FF7A45;
}
}
.legend-text {
font-size: 22rpx;
color: @text-secondary;
}
}
}
}
.bar-chart-container {
width: 100%;
}
}
.variance-list {
.variance-item {
display: flex;
align-items: center;
padding: 16rpx;
margin-bottom: 12rpx;
border-radius: 12rpx;
border: 1rpx solid #f0f0f0;
&.severe {
background: rgba(255, 77, 79, 0.05);
border-color: rgba(255, 77, 79, 0.2);
}
&.high {
background: rgba(255, 122, 69, 0.05);
border-color: rgba(255, 122, 69, 0.2);
}
&.medium {
background: rgba(250, 173, 20, 0.05);
border-color: rgba(250, 173, 20, 0.2);
}
&.low {
background: rgba(82, 196, 26, 0.05);
border-color: rgba(82, 196, 26, 0.2);
}
.variance-rank {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: @primary-color;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rpx;
font-weight: 600;
margin-right: 16rpx;
}
.variance-content {
flex: 1;
.product-name {
font-size: 28rpx;
color: @text-primary;
font-weight: 500;
display: block;
margin-bottom: 4rpx;
}
.product-category {
font-size: 22rpx;
color: @text-light;
display: block;
}
}
.variance-data {
display: flex;
gap: 24rpx;
margin-right: 16rpx;
.variance-info {
text-align: center;
.variance-label {
font-size: 20rpx;
color: @text-secondary;
display: block;
margin-bottom: 4rpx;
}
.variance-value {
font-size: 24rpx;
color: @text-primary;
font-weight: 600;
display: block;
}
}
}
.variance-percentage {
text-align: right;
.variance-rate {
font-size: 24rpx;
font-weight: 600;
color: @error-color;
display: block;
margin-bottom: 4rpx;
&.negative {
color: @error-color;
}
}
.variance-amount {
font-size: 22rpx;
color: @text-secondary;
display: block;
}
}
}
}
.suggestions {
.suggestion-item {
display: flex;
align-items: flex-start;
padding: 16rpx;
margin-bottom: 12rpx;
background: #fafafa;
border-radius: 12rpx;
.suggestion-icon {
font-size: 32rpx;
margin-right: 16rpx;
margin-top: 4rpx;
}
.suggestion-content {
flex: 1;
.suggestion-title {
font-size: 26rpx;
color: @text-primary;
font-weight: 500;
display: block;
margin-bottom: 8rpx;
}
.suggestion-desc {
font-size: 22rpx;
color: @text-secondary;
line-height: 1.5;
display: block;
}
}
}
}
}
}
</style>