|
@@ -9,7 +9,8 @@ import {
|
|
|
THEME
|
|
THEME
|
|
|
} from '@/utils/kb'
|
|
} from '@/utils/kb'
|
|
|
|
|
|
|
|
-type ActivePanel = 'distribution' | 'trend'
|
|
|
|
|
|
|
+import { IotStatApi } from '@/api/pms/stat'
|
|
|
|
|
+import dayjs from 'dayjs'
|
|
|
|
|
|
|
|
type InventoryItem = {
|
|
type InventoryItem = {
|
|
|
project: string
|
|
project: string
|
|
@@ -18,7 +19,42 @@ type InventoryItem = {
|
|
|
mayBacklogAmount: number
|
|
mayBacklogAmount: number
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+type InventoryDistributionResponse = {
|
|
|
|
|
+ totalInventory: number
|
|
|
|
|
+ totalOverStock: number
|
|
|
|
|
+ factoryNameOverStockPair: Record<string, number>
|
|
|
|
|
+ factoryNameInventoryPair: Record<string, number>
|
|
|
|
|
+ storageNameOverStockPair?: Record<string, number>
|
|
|
|
|
+ storageNameInventoryPair?: Record<string, number>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type InventoryAgingResponse = Record<string, number>
|
|
|
|
|
+
|
|
|
|
|
+type InventoryAgingPoint = {
|
|
|
|
|
+ month: string
|
|
|
|
|
+ value: number
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type InventoryDetail = {
|
|
|
|
|
+ '1年以内': number
|
|
|
|
|
+ '3年以上': number
|
|
|
|
|
+ 年初存货: number
|
|
|
|
|
+ 年初积压: number
|
|
|
|
|
+ '1-2年': number
|
|
|
|
|
+ 期末积压: number
|
|
|
|
|
+ '2-3年': number
|
|
|
|
|
+ 积压比: number
|
|
|
|
|
+ 期末库存: number
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+type ActivePanel = 'distribution' | 'trend' | 'detail'
|
|
|
|
|
+
|
|
|
const activePanel = ref<ActivePanel>('distribution')
|
|
const activePanel = ref<ActivePanel>('distribution')
|
|
|
|
|
+const DEFAULT_DATE = dayjs().subtract(1, 'day').format('YYYY-MM-DD')
|
|
|
|
|
+const selectedDate = ref(DEFAULT_DATE)
|
|
|
|
|
+const inventoryResult = ref<InventoryDistributionResponse | null>(null)
|
|
|
|
|
+const inventoryAgingResult = ref<InventoryAgingResponse>({})
|
|
|
|
|
+const inventoryDetailResult = ref<InventoryDetail | null>(null)
|
|
|
const distributionChartRef = ref<HTMLDivElement>()
|
|
const distributionChartRef = ref<HTMLDivElement>()
|
|
|
const trendChartRef = ref<HTMLDivElement>()
|
|
const trendChartRef = ref<HTMLDivElement>()
|
|
|
|
|
|
|
@@ -26,73 +62,66 @@ let distributionChart: echarts.ECharts | null = null
|
|
|
let trendChart: echarts.ECharts | null = null
|
|
let trendChart: echarts.ECharts | null = null
|
|
|
|
|
|
|
|
const panelOptions: Array<{ label: string; value: ActivePanel }> = [
|
|
const panelOptions: Array<{ label: string; value: ActivePanel }> = [
|
|
|
- { label: '分布', value: 'distribution' },
|
|
|
|
|
- { label: '趋势', value: 'trend' }
|
|
|
|
|
|
|
+ { label: '存货分布', value: 'distribution' },
|
|
|
|
|
+ { label: '趋势', value: 'trend' },
|
|
|
|
|
+ { label: '明细', value: 'detail' }
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
|
|
+const activeTitle = computed(() => {
|
|
|
|
|
+ if (activePanel.value === 'trend') return '积压趋势'
|
|
|
|
|
+ if (activePanel.value === 'detail') return '积压明细'
|
|
|
|
|
+ return '存货分布'
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
const yuanToWan = (value: number) => Number((value / 10000).toFixed(2))
|
|
const yuanToWan = (value: number) => Number((value / 10000).toFixed(2))
|
|
|
|
|
|
|
|
-const inventoryData: InventoryItem[] = [
|
|
|
|
|
- {
|
|
|
|
|
- project: '东营库',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(2921827.56),
|
|
|
|
|
- yearBeginningBacklog: yuanToWan(1644059.52),
|
|
|
|
|
- mayBacklogAmount: yuanToWan(1436126.52)
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '川庆',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(491050.94),
|
|
|
|
|
- yearBeginningBacklog: 0,
|
|
|
|
|
- mayBacklogAmount: yuanToWan(308801.56)
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '南美',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(2491993.31),
|
|
|
|
|
- yearBeginningBacklog: 0,
|
|
|
|
|
- mayBacklogAmount: 0
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '非洲',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(2276836.24),
|
|
|
|
|
- yearBeginningBacklog: yuanToWan(175144.46),
|
|
|
|
|
- mayBacklogAmount: yuanToWan(391697.89)
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '中东',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(127300.64),
|
|
|
|
|
- yearBeginningBacklog: yuanToWan(14784.43),
|
|
|
|
|
- mayBacklogAmount: yuanToWan(103461.07)
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '中亚',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(188389.42),
|
|
|
|
|
- yearBeginningBacklog: 0,
|
|
|
|
|
- mayBacklogAmount: 0
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '塔河库',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(17175342.26),
|
|
|
|
|
- yearBeginningBacklog: yuanToWan(9890389.23),
|
|
|
|
|
- mayBacklogAmount: yuanToWan(9261631.2)
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '塔里木',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(4599437.38),
|
|
|
|
|
- yearBeginningBacklog: 0,
|
|
|
|
|
- mayBacklogAmount: yuanToWan(890890.45)
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- project: '吐哈库',
|
|
|
|
|
- mayInventoryAmount: yuanToWan(2342089.06),
|
|
|
|
|
- yearBeginningBacklog: yuanToWan(1097925.36),
|
|
|
|
|
- mayBacklogAmount: yuanToWan(1190879.22)
|
|
|
|
|
|
|
+function formatAmount(value: number) {
|
|
|
|
|
+ return Number(value || 0).toFixed(2)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function formatRatio(value: number) {
|
|
|
|
|
+ return `${(Number(value || 0) * 100).toFixed(2)}%`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function formatWanValue(value: number) {
|
|
|
|
|
+ return formatAmount(yuanToWan(Number(value || 0)))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const detailTableData = computed(() => {
|
|
|
|
|
+ const data = inventoryDetailResult.value
|
|
|
|
|
+ if (!data) return []
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ {
|
|
|
|
|
+ beginningInventory: formatWanValue(data['年初存货']),
|
|
|
|
|
+ beginningOverStock: formatWanValue(data['年初积压']),
|
|
|
|
|
+ endingInventory: formatWanValue(data['期末库存']),
|
|
|
|
|
+ endingOverStock: formatWanValue(data['期末积压']),
|
|
|
|
|
+ withinOneYear: formatWanValue(data['1年以内']),
|
|
|
|
|
+ oneToTwoYears: formatWanValue(data['1-2年']),
|
|
|
|
|
+ twoToThreeYears: formatWanValue(data['2-3年']),
|
|
|
|
|
+ overThreeYears: formatWanValue(data['3年以上']),
|
|
|
|
|
+ overStockRatio: formatRatio(data['积压比'])
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+function getFactoryInventoryData(data: InventoryDistributionResponse | null): InventoryItem[] {
|
|
|
|
|
+ if (!data) {
|
|
|
|
|
+ return []
|
|
|
}
|
|
}
|
|
|
-]
|
|
|
|
|
|
|
|
|
|
-const activeTitle = computed(() => (activePanel.value === 'distribution' ? '存货分布' : '积压趋势'))
|
|
|
|
|
|
|
+ const factoryNames = new Set([
|
|
|
|
|
+ ...Object.keys(data.factoryNameInventoryPair || {}),
|
|
|
|
|
+ ...Object.keys(data.factoryNameOverStockPair || {})
|
|
|
|
|
+ ])
|
|
|
|
|
|
|
|
-function formatAmount(value: number) {
|
|
|
|
|
- return Number(value || 0).toFixed(2)
|
|
|
|
|
|
|
+ return [...factoryNames].map((project) => ({
|
|
|
|
|
+ project,
|
|
|
|
|
+ mayInventoryAmount: yuanToWan(data.factoryNameInventoryPair?.[project] || 0),
|
|
|
|
|
+ yearBeginningBacklog: 0,
|
|
|
|
|
+ mayBacklogAmount: yuanToWan(data.factoryNameOverStockPair?.[project] || 0)
|
|
|
|
|
+ }))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function getChartLayout(chartRef: Ref<HTMLDivElement | undefined>) {
|
|
function getChartLayout(chartRef: Ref<HTMLDivElement | undefined>) {
|
|
@@ -101,14 +130,14 @@ function getChartLayout(chartRef: Ref<HTMLDivElement | undefined>) {
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
compact,
|
|
compact,
|
|
|
- distributionTitleTop: compact ? 6 : 18,
|
|
|
|
|
- distributionTitleFontSize: compact ? 12 : 14,
|
|
|
|
|
|
|
+ distributionTitleTop: compact ? 3 : 13,
|
|
|
|
|
+ distributionTitleFontSize: compact ? 9 : 11,
|
|
|
distributionTitleLineHeight: compact ? 14 : 16,
|
|
distributionTitleLineHeight: compact ? 14 : 16,
|
|
|
- distributionPieRadius: compact ? ['36%', '54%'] : ['48%', '68%'],
|
|
|
|
|
- distributionPieCenterY: compact ? '62%' : '57%',
|
|
|
|
|
|
|
+ distributionPieRadius: compact ? ['38%', '50%'] : ['40%', '52%'],
|
|
|
|
|
+ distributionPieCenterY: compact ? '60%' : '57%',
|
|
|
distributionLegendBottom: compact ? 0 : 10,
|
|
distributionLegendBottom: compact ? 0 : 10,
|
|
|
distributionLegendItemSize: compact ? 9 : 13,
|
|
distributionLegendItemSize: compact ? 9 : 13,
|
|
|
- distributionLegendGap: compact ? 8 : 14,
|
|
|
|
|
|
|
+ distributionLegendGap: compact ? 4 : 10,
|
|
|
distributionLegendFontSize: compact ? 10 : 14,
|
|
distributionLegendFontSize: compact ? 10 : 14,
|
|
|
trendGridTop: compact ? 10 : 32,
|
|
trendGridTop: compact ? 10 : 32,
|
|
|
trendGridRight: compact ? 12 : THEME.grid.right,
|
|
trendGridRight: compact ? 12 : THEME.grid.right,
|
|
@@ -129,24 +158,34 @@ function getChartLayout(chartRef: Ref<HTMLDivElement | undefined>) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function getDistributionOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
|
|
|
|
+function getDistributionOption(
|
|
|
|
|
+ data: InventoryItem[],
|
|
|
|
|
+ totals?: Pick<InventoryDistributionResponse, 'totalInventory' | 'totalOverStock'>
|
|
|
|
|
+): echarts.EChartsOption {
|
|
|
const layout = getChartLayout(distributionChartRef)
|
|
const layout = getChartLayout(distributionChartRef)
|
|
|
- const inventoryTotal = data.reduce((total, item) => total + item.mayInventoryAmount, 0)
|
|
|
|
|
- const backlogTotal = data.reduce((total, item) => total + item.mayBacklogAmount, 0)
|
|
|
|
|
|
|
+ const distributionColors = [
|
|
|
|
|
+ THEME.color.blue.line,
|
|
|
|
|
+ THEME.color.orange.line,
|
|
|
|
|
+ THEME.color.green.line,
|
|
|
|
|
+ THEME.color.red.line,
|
|
|
|
|
+ THEME.color.blue.mid,
|
|
|
|
|
+ THEME.color.orange.mid,
|
|
|
|
|
+ THEME.color.green.mid,
|
|
|
|
|
+ THEME.color.red.mid,
|
|
|
|
|
+ THEME.color.blue.light
|
|
|
|
|
+ ]
|
|
|
|
|
+ const inventoryTotal =
|
|
|
|
|
+ totals?.totalInventory != null
|
|
|
|
|
+ ? yuanToWan(totals.totalInventory)
|
|
|
|
|
+ : data.reduce((total, item) => total + item.mayInventoryAmount, 0)
|
|
|
|
|
+ const backlogTotal =
|
|
|
|
|
+ totals?.totalOverStock != null
|
|
|
|
|
+ ? yuanToWan(totals.totalOverStock)
|
|
|
|
|
+ : data.reduce((total, item) => total + item.mayBacklogAmount, 0)
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
...ANIMATION,
|
|
...ANIMATION,
|
|
|
- color: [
|
|
|
|
|
- THEME.color.blue.line,
|
|
|
|
|
- THEME.color.orange.line,
|
|
|
|
|
- THEME.color.green.line,
|
|
|
|
|
- THEME.color.red.line,
|
|
|
|
|
- THEME.color.blue.mid,
|
|
|
|
|
- THEME.color.orange.mid,
|
|
|
|
|
- THEME.color.green.mid,
|
|
|
|
|
- THEME.color.red.mid,
|
|
|
|
|
- THEME.color.blue.light
|
|
|
|
|
- ],
|
|
|
|
|
|
|
+ color: distributionColors,
|
|
|
tooltip: createTooltip({
|
|
tooltip: createTooltip({
|
|
|
trigger: 'item',
|
|
trigger: 'item',
|
|
|
formatter(params: any) {
|
|
formatter(params: any) {
|
|
@@ -157,9 +196,9 @@ function getDistributionOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
}),
|
|
}),
|
|
|
title: [
|
|
title: [
|
|
|
{
|
|
{
|
|
|
- text: `5月底余额\n${formatAmount(inventoryTotal)} 万元`,
|
|
|
|
|
- left: '26.5%',
|
|
|
|
|
- top: layout.distributionTitleTop,
|
|
|
|
|
|
|
+ text: '各单位存货占比分布',
|
|
|
|
|
+ left: '20.5%',
|
|
|
|
|
+ top: 4,
|
|
|
textAlign: 'center',
|
|
textAlign: 'center',
|
|
|
textStyle: {
|
|
textStyle: {
|
|
|
color: THEME.text.strong,
|
|
color: THEME.text.strong,
|
|
@@ -170,9 +209,9 @@ function getDistributionOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- text: `5月底积压\n${formatAmount(backlogTotal)} 万元`,
|
|
|
|
|
- left: '72.5%',
|
|
|
|
|
- top: layout.distributionTitleTop,
|
|
|
|
|
|
|
+ text: '各单位积压占比分布',
|
|
|
|
|
+ left: '69.5%',
|
|
|
|
|
+ top: 4,
|
|
|
textAlign: 'center',
|
|
textAlign: 'center',
|
|
|
textStyle: {
|
|
textStyle: {
|
|
|
color: THEME.text.strong,
|
|
color: THEME.text.strong,
|
|
@@ -198,61 +237,186 @@ function getDistributionOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
fontFamily: FONT_FAMILY
|
|
fontFamily: FONT_FAMILY
|
|
|
}
|
|
}
|
|
|
}),
|
|
}),
|
|
|
|
|
+ graphic: [
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'text',
|
|
|
|
|
+ left: '19.5%',
|
|
|
|
|
+ top: '45%',
|
|
|
|
|
+ style: {
|
|
|
|
|
+ text: `总库存\n${formatAmount(inventoryTotal)}万元`,
|
|
|
|
|
+ textAlign: 'center',
|
|
|
|
|
+ fill: THEME.text.strong,
|
|
|
|
|
+ fontSize: layout.compact ? 8 : 10,
|
|
|
|
|
+ fontWeight: 700,
|
|
|
|
|
+ lineHeight: layout.distributionTitleLineHeight + 6,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ type: 'text',
|
|
|
|
|
+ left: '67%',
|
|
|
|
|
+ top: '45%',
|
|
|
|
|
+ style: {
|
|
|
|
|
+ text: `总积压\n${formatAmount(backlogTotal)}万元`,
|
|
|
|
|
+ textAlign: 'center',
|
|
|
|
|
+ fill: THEME.text.strong,
|
|
|
|
|
+ fontSize: layout.compact ? 8 : 10,
|
|
|
|
|
+ fontWeight: 700,
|
|
|
|
|
+ lineHeight: layout.distributionTitleLineHeight + 6,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
- name: '5月底余额',
|
|
|
|
|
|
|
+ name: '库存',
|
|
|
type: 'pie',
|
|
type: 'pie',
|
|
|
radius: layout.distributionPieRadius,
|
|
radius: layout.distributionPieRadius,
|
|
|
- center: ['27%', layout.distributionPieCenterY],
|
|
|
|
|
|
|
+ center: ['25%', layout.distributionPieCenterY],
|
|
|
minAngle: 5,
|
|
minAngle: 5,
|
|
|
|
|
+ avoidLabelOverlap: false,
|
|
|
label: {
|
|
label: {
|
|
|
- show: false
|
|
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: 'outside',
|
|
|
|
|
+ alignTo: 'labelLine',
|
|
|
|
|
+ bleedMargin: 0,
|
|
|
|
|
+ formatter: '{b}\n{d}%',
|
|
|
|
|
+ color: 'inherit',
|
|
|
|
|
+ fontSize: layout.labelFontSize,
|
|
|
|
|
+ fontWeight: 500,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
},
|
|
},
|
|
|
- data: data.map((item) => ({
|
|
|
|
|
|
|
+ labelLine: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ // length: layout.compact ? 6 : 10,
|
|
|
|
|
+ // length2: layout.compact ? 8 : 14,
|
|
|
|
|
+ minTurnAngle: 90,
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: distributionColors[0],
|
|
|
|
|
+ width: 1.5,
|
|
|
|
|
+ opacity: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLayout: {
|
|
|
|
|
+ hideOverlap: false
|
|
|
|
|
+ },
|
|
|
|
|
+ data: data.map((item, index) => ({
|
|
|
name: item.project,
|
|
name: item.project,
|
|
|
- value: item.mayInventoryAmount
|
|
|
|
|
|
|
+ value: item.mayInventoryAmount,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ color: distributionColors[index % distributionColors.length]
|
|
|
|
|
+ },
|
|
|
|
|
+ label: {
|
|
|
|
|
+ color: distributionColors[index % distributionColors.length]
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLine: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: distributionColors[index % distributionColors.length],
|
|
|
|
|
+ width: 1.5,
|
|
|
|
|
+ opacity: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}))
|
|
}))
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
- name: '5月底积压',
|
|
|
|
|
|
|
+ name: '积压库存',
|
|
|
type: 'pie',
|
|
type: 'pie',
|
|
|
radius: layout.distributionPieRadius,
|
|
radius: layout.distributionPieRadius,
|
|
|
center: ['73%', layout.distributionPieCenterY],
|
|
center: ['73%', layout.distributionPieCenterY],
|
|
|
minAngle: 5,
|
|
minAngle: 5,
|
|
|
|
|
+ avoidLabelOverlap: false,
|
|
|
label: {
|
|
label: {
|
|
|
- show: false
|
|
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ position: 'outside',
|
|
|
|
|
+ alignTo: 'labelLine',
|
|
|
|
|
+ bleedMargin: 0,
|
|
|
|
|
+ formatter: '{b}\n{d}%',
|
|
|
|
|
+ color: 'inherit',
|
|
|
|
|
+ fontSize: layout.labelFontSize,
|
|
|
|
|
+ fontWeight: 500,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLine: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ // length: layout.compact ? 6 : 10,
|
|
|
|
|
+ // length2: layout.compact ? 8 : 14,
|
|
|
|
|
+ minTurnAngle: 90,
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: distributionColors[0],
|
|
|
|
|
+ width: 1.5,
|
|
|
|
|
+ opacity: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLayout: {
|
|
|
|
|
+ hideOverlap: false
|
|
|
},
|
|
},
|
|
|
data: data
|
|
data: data
|
|
|
.filter((item) => item.mayBacklogAmount > 0)
|
|
.filter((item) => item.mayBacklogAmount > 0)
|
|
|
- .map((item) => ({
|
|
|
|
|
|
|
+ .map((item, index) => ({
|
|
|
name: item.project,
|
|
name: item.project,
|
|
|
- value: item.mayBacklogAmount
|
|
|
|
|
|
|
+ value: item.mayBacklogAmount,
|
|
|
|
|
+ itemStyle: {
|
|
|
|
|
+ color: distributionColors[index % distributionColors.length]
|
|
|
|
|
+ },
|
|
|
|
|
+ label: {
|
|
|
|
|
+ color: distributionColors[index % distributionColors.length]
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLine: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ color: distributionColors[index % distributionColors.length],
|
|
|
|
|
+ width: 1.5,
|
|
|
|
|
+ opacity: 1
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}))
|
|
}))
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function getTrendOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
|
|
- const layout = getChartLayout(trendChartRef)
|
|
|
|
|
- const maxBacklog = Math.max(
|
|
|
|
|
- ...data.map((item) => Math.max(item.yearBeginningBacklog, item.mayBacklogAmount)),
|
|
|
|
|
- 1
|
|
|
|
|
- )
|
|
|
|
|
- const backlogAxisMax = Math.ceil((maxBacklog * 1.15) / 100) * 100
|
|
|
|
|
- const barLabel = {
|
|
|
|
|
- show: true,
|
|
|
|
|
- position: 'right' as any,
|
|
|
|
|
- distance: layout.labelDistance,
|
|
|
|
|
- color: THEME.text.strong,
|
|
|
|
|
- fontSize: layout.labelFontSize,
|
|
|
|
|
- fontWeight: 700,
|
|
|
|
|
- fontFamily: FONT_FAMILY,
|
|
|
|
|
- formatter(params: any) {
|
|
|
|
|
- return formatAmount(Number(params.value))
|
|
|
|
|
- }
|
|
|
|
|
|
|
+function initChart(
|
|
|
|
|
+ chartRef: Ref<HTMLDivElement | undefined>,
|
|
|
|
|
+ chart: echarts.ECharts | null,
|
|
|
|
|
+ option: echarts.EChartsOption
|
|
|
|
|
+) {
|
|
|
|
|
+ if (!chartRef.value) return chart
|
|
|
|
|
+
|
|
|
|
|
+ chart?.dispose()
|
|
|
|
|
+ const nextChart = echarts.init(chartRef.value, undefined, {
|
|
|
|
|
+ renderer: CHART_RENDERER
|
|
|
|
|
+ })
|
|
|
|
|
+ nextChart.setOption(option, true)
|
|
|
|
|
+
|
|
|
|
|
+ return nextChart
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getInventoryAgingPoints(data: unknown): InventoryAgingPoint[] {
|
|
|
|
|
+ if (Array.isArray(data)) {
|
|
|
|
|
+ return data
|
|
|
|
|
+ .map((item: any) => ({
|
|
|
|
|
+ month: item?.month ?? item?.date ?? item?.fdate,
|
|
|
|
|
+ value: Number(item?.value ?? item?.amount ?? item?.overStockAmount)
|
|
|
|
|
+ }))
|
|
|
|
|
+ .filter((item) => /^\d{4}-\d{2}$/.test(item.month) && Number.isFinite(item.value))
|
|
|
|
|
+ .sort((itemA, itemB) => itemA.month.localeCompare(itemB.month))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (!data || typeof data !== 'object') return []
|
|
|
|
|
+
|
|
|
|
|
+ return Object.entries(data)
|
|
|
|
|
+ .map(([month, value]) => ({ month, value: Number(value) }))
|
|
|
|
|
+ .filter((item) => /^\d{4}-\d{2}$/.test(item.month) && Number.isFinite(item.value))
|
|
|
|
|
+ .sort((itemA, itemB) => itemA.month.localeCompare(itemB.month))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getInventoryAgingOption(data: unknown): echarts.EChartsOption {
|
|
|
|
|
+ const layout = getChartLayout(trendChartRef)
|
|
|
|
|
+ const entries = getInventoryAgingPoints(data)
|
|
|
|
|
+ const months = entries.map(({ month }) => month)
|
|
|
|
|
+ const values = entries.map(({ value }) => yuanToWan(value))
|
|
|
|
|
+
|
|
|
return {
|
|
return {
|
|
|
...ANIMATION,
|
|
...ANIMATION,
|
|
|
grid: {
|
|
grid: {
|
|
@@ -261,45 +425,28 @@ function getTrendOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
right: layout.trendGridRight,
|
|
right: layout.trendGridRight,
|
|
|
bottom: layout.trendGridBottom
|
|
bottom: layout.trendGridBottom
|
|
|
},
|
|
},
|
|
|
- color: [THEME.color.blue.line, THEME.color.orange.line],
|
|
|
|
|
- legend: createLegend(
|
|
|
|
|
- {
|
|
|
|
|
- top: layout.legendTop,
|
|
|
|
|
- right: layout.legendRight,
|
|
|
|
|
- itemWidth: layout.legendItemSize,
|
|
|
|
|
- itemHeight: layout.legendItemSize,
|
|
|
|
|
- itemGap: layout.legendGap,
|
|
|
|
|
- textStyle: {
|
|
|
|
|
- color: THEME.text.regular,
|
|
|
|
|
- fontSize: layout.legendFontSize,
|
|
|
|
|
- fontWeight: 600,
|
|
|
|
|
- fontFamily: FONT_FAMILY
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- ['年初积压', '5月底积压']
|
|
|
|
|
- ),
|
|
|
|
|
tooltip: createTooltip({
|
|
tooltip: createTooltip({
|
|
|
trigger: 'axis',
|
|
trigger: 'axis',
|
|
|
- axisPointer: {
|
|
|
|
|
- type: 'shadow',
|
|
|
|
|
- shadowStyle: {
|
|
|
|
|
- color: THEME.split
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
valueFormatter(value: number) {
|
|
valueFormatter(value: number) {
|
|
|
return `${formatAmount(value)}万元`
|
|
return `${formatAmount(value)}万元`
|
|
|
}
|
|
}
|
|
|
}),
|
|
}),
|
|
|
xAxis: {
|
|
xAxis: {
|
|
|
|
|
+ type: 'category',
|
|
|
|
|
+ boundaryGap: false,
|
|
|
|
|
+ data: months,
|
|
|
|
|
+ axisTick: { show: false },
|
|
|
|
|
+ axisLabel: {
|
|
|
|
|
+ color: THEME.text.regular,
|
|
|
|
|
+ fontSize: layout.axisFontSize,
|
|
|
|
|
+ fontFamily: FONT_FAMILY
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ yAxis: {
|
|
|
type: 'value',
|
|
type: 'value',
|
|
|
- max: backlogAxisMax,
|
|
|
|
|
- splitNumber: 4,
|
|
|
|
|
- axisLine: {
|
|
|
|
|
- show: false
|
|
|
|
|
- },
|
|
|
|
|
- axisTick: {
|
|
|
|
|
- show: false
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ name: '万元',
|
|
|
|
|
+ min: 0,
|
|
|
|
|
+ axisTick: { show: false },
|
|
|
axisLabel: {
|
|
axisLabel: {
|
|
|
color: THEME.text.regular,
|
|
color: THEME.text.regular,
|
|
|
fontSize: layout.axisFontSize,
|
|
fontSize: layout.axisFontSize,
|
|
@@ -312,115 +459,73 @@ function getTrendOption(data: InventoryItem[]): echarts.EChartsOption {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- yAxis: {
|
|
|
|
|
- type: 'category',
|
|
|
|
|
- data: data.map((item) => item.project),
|
|
|
|
|
- inverse: true,
|
|
|
|
|
- axisLine: {
|
|
|
|
|
- show: false
|
|
|
|
|
- },
|
|
|
|
|
- axisTick: {
|
|
|
|
|
- show: false
|
|
|
|
|
- },
|
|
|
|
|
- axisLabel: {
|
|
|
|
|
- color: THEME.text.regular,
|
|
|
|
|
- fontSize: layout.axisFontSize,
|
|
|
|
|
- fontWeight: 600,
|
|
|
|
|
- fontFamily: FONT_FAMILY,
|
|
|
|
|
- margin: layout.yAxisLabelMargin,
|
|
|
|
|
- width: layout.yAxisLabelWidth,
|
|
|
|
|
- overflow: 'break',
|
|
|
|
|
- align: 'right'
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
- name: '年初积压',
|
|
|
|
|
- type: 'bar',
|
|
|
|
|
- data: data.map((item) => item.yearBeginningBacklog),
|
|
|
|
|
- barWidth: layout.barWidth,
|
|
|
|
|
- barGap: layout.barGap,
|
|
|
|
|
- barCategoryGap: layout.barCategoryGap,
|
|
|
|
|
- label: barLabel,
|
|
|
|
|
- labelLayout: {
|
|
|
|
|
- hideOverlap: false
|
|
|
|
|
|
|
+ name: '积压库存',
|
|
|
|
|
+ type: 'line',
|
|
|
|
|
+ smooth: true,
|
|
|
|
|
+ data: values,
|
|
|
|
|
+ symbol: 'circle',
|
|
|
|
|
+ symbolSize: layout.compact ? 6 : 8,
|
|
|
|
|
+ lineStyle: {
|
|
|
|
|
+ width: layout.compact ? 2 : 3,
|
|
|
|
|
+ color: THEME.color.orange.line
|
|
|
},
|
|
},
|
|
|
itemStyle: {
|
|
itemStyle: {
|
|
|
- shadowBlur: 10,
|
|
|
|
|
- shadowColor: THEME.color.blue.bg,
|
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
|
- { offset: 0, color: THEME.color.blue.light },
|
|
|
|
|
- { offset: 0.55, color: THEME.color.blue.mid },
|
|
|
|
|
- { offset: 1, color: THEME.color.blue.line }
|
|
|
|
|
- ])
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- name: '5月底积压',
|
|
|
|
|
- type: 'bar',
|
|
|
|
|
- data: data.map((item) => item.mayBacklogAmount),
|
|
|
|
|
- barWidth: layout.barWidth,
|
|
|
|
|
- barGap: layout.barGap,
|
|
|
|
|
- barCategoryGap: layout.barCategoryGap,
|
|
|
|
|
- label: barLabel,
|
|
|
|
|
- labelLayout: {
|
|
|
|
|
- hideOverlap: false
|
|
|
|
|
|
|
+ color: THEME.color.orange.line
|
|
|
},
|
|
},
|
|
|
- itemStyle: {
|
|
|
|
|
- shadowBlur: 10,
|
|
|
|
|
- shadowColor: THEME.color.orange.bg,
|
|
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
|
|
|
|
- { offset: 0, color: THEME.color.orange.light },
|
|
|
|
|
- { offset: 0.55, color: THEME.color.orange.mid },
|
|
|
|
|
- { offset: 1, color: THEME.color.orange.line }
|
|
|
|
|
|
|
+ areaStyle: {
|
|
|
|
|
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
+ { offset: 0, color: 'rgb(255 161 79 / 28%)' },
|
|
|
|
|
+ { offset: 1, color: 'rgb(255 161 79 / 2%)' }
|
|
|
])
|
|
])
|
|
|
|
|
+ },
|
|
|
|
|
+ label: {
|
|
|
|
|
+ show: true,
|
|
|
|
|
+ color: THEME.color.orange.line,
|
|
|
|
|
+ fontSize: layout.labelFontSize,
|
|
|
|
|
+ fontFamily: FONT_FAMILY,
|
|
|
|
|
+ formatter(params: any) {
|
|
|
|
|
+ return formatAmount(Number(params.value))
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
]
|
|
]
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function initChart(
|
|
|
|
|
- chartRef: Ref<HTMLDivElement | undefined>,
|
|
|
|
|
- chart: echarts.ECharts | null,
|
|
|
|
|
- option: echarts.EChartsOption
|
|
|
|
|
-) {
|
|
|
|
|
- if (!chartRef.value) return chart
|
|
|
|
|
-
|
|
|
|
|
- chart?.dispose()
|
|
|
|
|
- const nextChart = echarts.init(chartRef.value, undefined, {
|
|
|
|
|
- renderer: CHART_RENDERER
|
|
|
|
|
- })
|
|
|
|
|
- nextChart.setOption(option, true)
|
|
|
|
|
-
|
|
|
|
|
- return nextChart
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
function renderDistributionChart() {
|
|
function renderDistributionChart() {
|
|
|
- distributionChart?.setOption(getDistributionOption(inventoryData), true)
|
|
|
|
|
|
|
+ const data = getFactoryInventoryData(inventoryResult.value)
|
|
|
|
|
+ distributionChart?.setOption(
|
|
|
|
|
+ getDistributionOption(data, inventoryResult.value || undefined),
|
|
|
|
|
+ true
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function renderTrendChart() {
|
|
function renderTrendChart() {
|
|
|
- trendChart?.setOption(getTrendOption(inventoryData), true)
|
|
|
|
|
|
|
+ trendChart?.setOption(getInventoryAgingOption(inventoryAgingResult.value), true)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function initDistributionChart() {
|
|
function initDistributionChart() {
|
|
|
|
|
+ const data = getFactoryInventoryData(inventoryResult.value)
|
|
|
distributionChart = initChart(
|
|
distributionChart = initChart(
|
|
|
distributionChartRef,
|
|
distributionChartRef,
|
|
|
distributionChart,
|
|
distributionChart,
|
|
|
- getDistributionOption(inventoryData)
|
|
|
|
|
|
|
+ getDistributionOption(data, inventoryResult.value || undefined)
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function initTrendChart() {
|
|
function initTrendChart() {
|
|
|
- trendChart = initChart(trendChartRef, trendChart, getTrendOption(inventoryData))
|
|
|
|
|
|
|
+ trendChart = initChart(
|
|
|
|
|
+ trendChartRef,
|
|
|
|
|
+ trendChart,
|
|
|
|
|
+ getInventoryAgingOption(inventoryAgingResult.value)
|
|
|
|
|
+ )
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function resizeCharts() {
|
|
function resizeCharts() {
|
|
|
distributionChart?.resize()
|
|
distributionChart?.resize()
|
|
|
trendChart?.resize()
|
|
trendChart?.resize()
|
|
|
- renderDistributionChart()
|
|
|
|
|
- renderTrendChart()
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function destroyCharts() {
|
|
function destroyCharts() {
|
|
@@ -435,20 +540,103 @@ watch(activePanel, (value) => {
|
|
|
if (value === 'distribution') {
|
|
if (value === 'distribution') {
|
|
|
if (!distributionChart) initDistributionChart()
|
|
if (!distributionChart) initDistributionChart()
|
|
|
renderDistributionChart()
|
|
renderDistributionChart()
|
|
|
|
|
+ } else if (value === 'trend') {
|
|
|
|
|
+ requestInventoryAging()
|
|
|
} else {
|
|
} else {
|
|
|
- if (!trendChart) initTrendChart()
|
|
|
|
|
- renderTrendChart()
|
|
|
|
|
|
|
+ requestInventoryDetail()
|
|
|
}
|
|
}
|
|
|
- resizeCharts()
|
|
|
|
|
})
|
|
})
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+async function requestInventoryAging() {
|
|
|
|
|
+ if (deptId.value === null || !selectedDate.value) return
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await IotStatApi.getInventoryAging({
|
|
|
|
|
+ fdate: selectedDate.value,
|
|
|
|
|
+ dept: deptId.value
|
|
|
|
|
+ })
|
|
|
|
|
+ const data = response?.data?.data ?? response?.data ?? response
|
|
|
|
|
+
|
|
|
|
|
+ const points = getInventoryAgingPoints(data)
|
|
|
|
|
+
|
|
|
|
|
+ console.log('库存积压趋势数据', points)
|
|
|
|
|
+
|
|
|
|
|
+ if (points.length) {
|
|
|
|
|
+ inventoryAgingResult.value = Object.fromEntries(
|
|
|
|
|
+ points.map(({ month, value }) => [month, value])
|
|
|
|
|
+ )
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ if (!trendChart) initTrendChart()
|
|
|
|
|
+ renderTrendChart()
|
|
|
|
|
+ })
|
|
|
|
|
+ } else if (trendChart) {
|
|
|
|
|
+ trendChart.setOption(getInventoryAgingOption({}), true)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取库存积压趋势数据失败', error)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function requestInventoryDistribution() {
|
|
|
|
|
+ if (deptId.value === null || !selectedDate.value) return
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await IotStatApi.getInventoryDistribution({
|
|
|
|
|
+ fdate: selectedDate.value,
|
|
|
|
|
+ dept: deptId.value
|
|
|
|
|
+ })
|
|
|
|
|
+ const data = response
|
|
|
|
|
+
|
|
|
|
|
+ if (data && typeof data === 'object') {
|
|
|
|
|
+ inventoryResult.value = data as InventoryDistributionResponse
|
|
|
|
|
+ renderDistributionChart()
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取库存分布数据失败', error)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function requestInventoryDetail() {
|
|
|
|
|
+ if (deptId.value === null || !selectedDate.value) return
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await IotStatApi.getInventoryDetail({
|
|
|
|
|
+ fdate: selectedDate.value,
|
|
|
|
|
+ dept: deptId.value
|
|
|
|
|
+ })
|
|
|
|
|
+ const data = response?.data?.data ?? response?.data ?? response
|
|
|
|
|
+
|
|
|
|
|
+ if (data && typeof data === 'object') {
|
|
|
|
|
+ inventoryDetailResult.value = data as InventoryDetail
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取库存明细数据失败', error)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
initDistributionChart()
|
|
initDistributionChart()
|
|
|
window.addEventListener('resize', resizeCharts)
|
|
window.addEventListener('resize', resizeCharts)
|
|
|
window.addEventListener('rhkb:resize', resizeCharts)
|
|
window.addEventListener('rhkb:resize', resizeCharts)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+let deptId = ref<number | string>('157')
|
|
|
|
|
+
|
|
|
|
|
+onMounted(async () => {
|
|
|
|
|
+ await requestInventoryDistribution()
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+watch(selectedDate, () => {
|
|
|
|
|
+ if (activePanel.value === 'distribution') {
|
|
|
|
|
+ requestInventoryDistribution()
|
|
|
|
|
+ } else if (activePanel.value === 'trend') {
|
|
|
|
|
+ requestInventoryAging()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ requestInventoryDetail()
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
onUnmounted(() => {
|
|
onUnmounted(() => {
|
|
|
window.removeEventListener('resize', resizeCharts)
|
|
window.removeEventListener('resize', resizeCharts)
|
|
|
window.removeEventListener('rhkb:resize', resizeCharts)
|
|
window.removeEventListener('rhkb:resize', resizeCharts)
|
|
@@ -466,18 +654,69 @@ onUnmounted(() => {
|
|
|
</div>
|
|
</div>
|
|
|
{{ activeTitle }}
|
|
{{ activeTitle }}
|
|
|
</div>
|
|
</div>
|
|
|
- <el-segmented
|
|
|
|
|
- v-model="activePanel"
|
|
|
|
|
- :options="panelOptions"
|
|
|
|
|
- size="small"
|
|
|
|
|
- class="inventory-switch" />
|
|
|
|
|
|
|
+ <div class="inventory-panel-actions">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="selectedDate"
|
|
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
|
|
+ type="date"
|
|
|
|
|
+ placeholder="选择日期"
|
|
|
|
|
+ :clearable="false"
|
|
|
|
|
+ style="width: 120px"
|
|
|
|
|
+ class="inventory-date-picker" />
|
|
|
|
|
+ <el-segmented
|
|
|
|
|
+ v-model="activePanel"
|
|
|
|
|
+ :options="panelOptions"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="inventory-switch" />
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
<div class="flex-1 min-h-0">
|
|
<div class="flex-1 min-h-0">
|
|
|
<div
|
|
<div
|
|
|
v-show="activePanel === 'distribution'"
|
|
v-show="activePanel === 'distribution'"
|
|
|
ref="distributionChartRef"
|
|
ref="distributionChartRef"
|
|
|
class="inventory-chart"></div>
|
|
class="inventory-chart"></div>
|
|
|
- <div v-show="activePanel === 'trend'" ref="trendChartRef" class="inventory-chart"></div>
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-show="activePanel === 'trend'"
|
|
|
|
|
+ ref="trendChartRef"
|
|
|
|
|
+ style="height: 80%; margin-top: 18px"
|
|
|
|
|
+ class="inventory-chart"></div>
|
|
|
|
|
+ <div v-show="activePanel === 'detail'" class="inventory-detail-layout">
|
|
|
|
|
+ <section class="inventory-detail-section">
|
|
|
|
|
+ <div class="inventory-detail-section__title">存货及变动情况</div>
|
|
|
|
|
+ <el-table :data="detailTableData" border class="inventory-detail-table">
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="beginningInventory"
|
|
|
|
|
+ label="年初存货"
|
|
|
|
|
+ min-width="92"
|
|
|
|
|
+ align="center" />
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="beginningOverStock"
|
|
|
|
|
+ label="年初积压"
|
|
|
|
|
+ min-width="92"
|
|
|
|
|
+ align="center" />
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="endingInventory"
|
|
|
|
|
+ label="期末库存"
|
|
|
|
|
+ min-width="92"
|
|
|
|
|
+ align="center" />
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ prop="endingOverStock"
|
|
|
|
|
+ label="期末积压"
|
|
|
|
|
+ min-width="92"
|
|
|
|
|
+ align="center" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </section>
|
|
|
|
|
+ <section class="inventory-detail-section">
|
|
|
|
|
+ <div class="inventory-detail-section__title">账龄分析</div>
|
|
|
|
|
+ <el-table :data="detailTableData" border class="inventory-detail-table">
|
|
|
|
|
+ <el-table-column prop="withinOneYear" label="1年以内" min-width="82" align="center" />
|
|
|
|
|
+ <el-table-column prop="oneToTwoYears" label="1-2年" min-width="74" align="center" />
|
|
|
|
|
+ <el-table-column prop="twoToThreeYears" label="2-3年" min-width="74" align="center" />
|
|
|
|
|
+ <el-table-column prop="overThreeYears" label="3年以上" min-width="82" align="center" />
|
|
|
|
|
+ <el-table-column prop="overStockRatio" label="积压比" min-width="78" align="center" />
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+ </section>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
@@ -485,6 +724,12 @@ onUnmounted(() => {
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
@import url('@/styles/kb.scss');
|
|
@import url('@/styles/kb.scss');
|
|
|
|
|
|
|
|
|
|
+.inventory-panel-actions {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: calc(8px * var(--kb-scale, 1));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
.inventory-switch {
|
|
.inventory-switch {
|
|
|
--el-segmented-item-selected-color: #03409b;
|
|
--el-segmented-item-selected-color: #03409b;
|
|
|
--el-segmented-item-selected-bg-color: rgb(255 255 255 / 86%);
|
|
--el-segmented-item-selected-bg-color: rgb(255 255 255 / 86%);
|
|
@@ -494,13 +739,29 @@ onUnmounted(() => {
|
|
|
min-height: calc(26px * var(--kb-scale, 1));
|
|
min-height: calc(26px * var(--kb-scale, 1));
|
|
|
padding: calc(2px * var(--kb-scale, 1));
|
|
padding: calc(2px * var(--kb-scale, 1));
|
|
|
border: 1px solid rgb(31 91 184 / 12%);
|
|
border: 1px solid rgb(31 91 184 / 12%);
|
|
|
- transform: translateY(calc(-2px * var(--kb-scale, 1)));
|
|
|
|
|
|
|
|
|
|
:deep(.el-segmented__item) {
|
|
:deep(.el-segmented__item) {
|
|
|
min-height: calc(22px * var(--kb-scale, 1));
|
|
min-height: calc(22px * var(--kb-scale, 1));
|
|
|
padding: 0 calc(8px * var(--kb-scale, 1));
|
|
padding: 0 calc(8px * var(--kb-scale, 1));
|
|
|
- font-size: calc(13px * var(--kb-scale, 1));
|
|
|
|
|
- font-weight: 600;
|
|
|
|
|
|
|
+ font-size: calc(12px * var(--kb-scale, 1));
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #29527f;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-date-picker {
|
|
|
|
|
+ width: calc(132px * var(--kb-scale, 1));
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-input__wrapper) {
|
|
|
|
|
+ min-height: calc(26px * var(--kb-scale, 1));
|
|
|
|
|
+ padding: 0 calc(7px * var(--kb-scale, 1));
|
|
|
|
|
+ background: rgb(255 255 255 / 82%);
|
|
|
|
|
+ border-radius: calc(4px * var(--kb-scale, 1));
|
|
|
|
|
+ box-shadow: 0 0 0 1px rgb(31 91 184 / 24%) inset;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-input__inner) {
|
|
|
|
|
+ font-size: calc(12px * var(--kb-scale, 1));
|
|
|
color: #29527f;
|
|
color: #29527f;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -510,4 +771,105 @@ onUnmounted(() => {
|
|
|
height: 100%;
|
|
height: 100%;
|
|
|
min-height: 0;
|
|
min-height: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-detail-table {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: auto;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+ color: #1d2f46;
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-table__inner-wrapper::before) {
|
|
|
|
|
+ background-color: rgb(31 91 184 / 28%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(th.el-table__cell) {
|
|
|
|
|
+ padding: calc(3px * var(--kb-scale, 1)) 0;
|
|
|
|
|
+ color: #073f8e;
|
|
|
|
|
+ font-size: calc(13px * var(--kb-scale, 1));
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+ border-color: rgb(31 91 184 / 24%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(th.el-table__cell .cell) {
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(td.el-table__cell) {
|
|
|
|
|
+ padding: calc(4px * var(--kb-scale, 1)) 0;
|
|
|
|
|
+ color: #1d2f46;
|
|
|
|
|
+ font-size: calc(13px * var(--kb-scale, 1));
|
|
|
|
|
+ border-color: rgb(31 91 184 / 20%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(.el-table__body tr:hover > td.el-table__cell) {
|
|
|
|
|
+ background-color: transparent;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ :deep(td.el-table__cell) {
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-detail-layout {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ padding-top: calc(10px * var(--kb-scale, 1));
|
|
|
|
|
+ gap: calc(12px * var(--kb-scale, 1));
|
|
|
|
|
+ grid-template-rows: repeat(2, minmax(0, 1fr));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-detail-section {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ min-height: 0;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-detail-section__title {
|
|
|
|
|
+ padding: 0 0 calc(5px * var(--kb-scale, 1));
|
|
|
|
|
+ font-size: calc(13px * var(--kb-scale, 1));
|
|
|
|
|
+ font-weight: 700;
|
|
|
|
|
+ color: #0b4a9c;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inventory-detail-section .inventory-detail-table {
|
|
|
|
|
+ flex: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table th {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table tr {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table td {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table th.el-table__cell {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+ border: none !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table .el-table__header-wrapper {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table thead {
|
|
|
|
|
+ background-color: transparent !important;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+::v-deep .el-table th.el-table__cell > .cell {
|
|
|
|
|
+ // color: rgba(255, 255, 255, 0.8) !important;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|