销售分析数据对接

This commit is contained in:
DESKTOP-AD8UBUJ\ling
2026-05-18 14:00:45 +08:00
parent 6e2e473725
commit 3176848d0f
2 changed files with 346 additions and 88 deletions

View File

@@ -20,27 +20,27 @@
</div>
<div class="stat-wrapper">
<span class="stat-value"><span>121</span>%</span>
<span class="stat-value"><span>{{statsData['市场渗透率']}}</span>%</span>
<div class="stat-bar">
<div class="bar-fill" style="width: 85%"></div>
<div class="bar-fill" :style="'width: '+ (statsData['市场渗透率']>100?100:statsData['市场渗透率'])+'%'"></div>
</div>
</div>
<div class="stat-row">
<span class="stat-label">回款率</span>
</div>
<div class="stat-wrapper">
<span class="stat-value"><span>62</span>%</span>
<span class="stat-value"><span>{{statsData['回款率']}}</span>%</span>
<div class="stat-bar">
<div class="bar-fill" style="width: 62%"></div>
<div class="bar-fill" :style="'width: '+ (statsData['回款率']>100?100:statsData['回款率'])+'%'"></div>
</div>
</div>
<div class="stat-row">
<span class="stat-label">目标达成率</span>
</div>
<div class="stat-wrapper">
<span class="stat-value"><span>62</span>%</span>
<span class="stat-value"><span>{{statsData['目标达成率']}}</span>%</span>
<div class="stat-bar">
<div class="bar-fill" style="width: 62%"></div>
<div class="bar-fill" :style="'width: '+ (statsData['目标达成率']>100?100:statsData['目标达成率'])+'%'"></div>
</div>
</div>
@@ -128,7 +128,7 @@
<div class="panel-card line-card">
<div class="card-header">
<span class="card-title">重点客户分析</span>
<span class="card-title">重点客户分析(销售额毛利)</span>
</div>
<div ref="lineChart" class="line-container"></div>
</div>
@@ -137,21 +137,21 @@
<aside class="right-panel">
<div class="panel-card product-card">
<div class="card-header">
<span class="card-title">重点产品分析</span>
<span class="card-title">重点产品分析(销售额毛利)</span>
</div>
<div ref="productBarChart" class="product-bar"></div>
</div>
<div class="panel-card product-card">
<div class="card-header">
<span class="card-title">重点产品分析</span>
<span class="card-title">重点产品分析(销量增长率)</span>
</div>
<div ref="productLineChart" class="product-line"></div>
</div>
<div class="panel-card product-card">
<div class="card-header">
<span class="card-title">重点产品分析</span>
<span class="card-title">重点客户分析(销量增长率)</span>
</div>
<div ref="trendChart" class="trend-container"></div>
</div>
@@ -162,12 +162,13 @@
<script>
import * as echarts from 'echarts'
import {getData} from '@/api/bigscreen'
export default {
name: 'SalesDashboard',
data() {
return {
charts: {}
charts: {},
statsData: {'市场渗透率':0,'回款率':0,'目标达成率':0}
}
},
mounted() {
@@ -200,9 +201,21 @@ export default {
this.initProductBarChart()
this.initProductLineChart()
this.initTrendChart()
this.initStats()
},
async initStats(){
initMainRingChart() {
},
async initMainRingChart() {
const params={"chartProperties":{"总销售额_万元":"text"},"setCode":"zhibiao","chartType":"widget-text","contextData":{"reportCode":"salesAnalysis2026"}}
const {code, data} = await getData(params);
if(code != 200){
console.error('[Viewer] 获取大屏数据失败:', code);
return;
}
const ringData = [{name:'销售额',value:data[0]['总销售额_万元'].split('万')[0]},{name:'毛利',value:data[0]['毛利'].split('万')[0]},{name:'增长率',value:data[0]['增长率']}]
const chart = echarts.init(this.$refs.mainRingChart)
const option = {
backgroundColor: 'transparent',
@@ -215,7 +228,7 @@ export default {
textStyle: {
color: '#fff'
},
data: ["销售额", "毛利", "完后率"]
data: ringData.map(item => item.name)
},
grid: {
top: 0,
@@ -247,18 +260,17 @@ export default {
},
color: ["#109BDC", "#FBB900", "#FF4D4F"],
radius: ['65%', '60%'],
data: [{ value: 1600,name:'销售额' },{ value: 1008,name:'毛利' },{ value: 98,name:'完后率' }]
data: ringData
}]
}
chart.setOption(option)
this.charts.mainRing = chart
// 数据列表
const dataList = [
{ name: '销售额', target: 1600 },
{ name: '毛利', target: 1008 },
{ name: '完成率', target: 98 }
]
const dataList = ringData.map(item => ({
name: item.name,
target: item.value
}))
let curIndex = 0
let timer = null
@@ -280,7 +292,7 @@ export default {
chart.setOption({
series: [{
label: {
formatter: `{a|${now+(name=='完成率'?'%':'万')}}\n\n{b|${name}}`
formatter: `{a|${now+(name=='增长率'?'%':'万')}}\n\n{b|${name}}`
}
}]
})
@@ -490,12 +502,15 @@ export default {
timer = setInterval(loopSwitch, 2000)
},
initMapChart() {
async initMapChart() {
const worldMap = await axios.get('../../../../static/world.json');
echarts.registerMap('world', worldMap.data);
const chart = echarts.init(this.$refs.mapChart)
const option = {
backgroundColor: 'transparent',
geo: {
map: 'world',
name: '世界地图',
roam: false,
itemStyle: {
areaColor: 'rgba(45, 65, 85, 0.6)',
@@ -529,7 +544,8 @@ export default {
rippleEffect: {
brushType: 'stroke'
}
}, {
}
, {
type: 'lines',
coordinateSystem: 'geo',
data: [
@@ -554,18 +570,23 @@ export default {
trailLength: 0.5,
color: '#ffc107'
}
}]
}
]
}
chart.setOption(option)
this.charts.map = chart
},
initBarChart() {
async initBarChart() {
const chart = echarts.init(this.$refs.barChart)
const regions = ['北区', '南区', '东区', '西区', '华东', '华南', '华北', '西南', '西北', '东北', '华中', '海外']
const salesData = [68, 65, 62, 58, 55, 52, 48, 45, 42, 38, 35, 30]
const profitData = [25, 22, 18, 15, 12, 8, 5, 3, 2, 1, 0, 0]
const params={"chartProperties":{"业务区域":"xAxis","销量":"bar"},"setCode":"scfx_zdqy","chartType":"widget-barchart","contextData":{"reportCode":"salesAnalysis2026"}}
const {code,data} = await getData(params)
if(code != 200){
return
}
const regions =data.map(item => item['业务区域'])
const salesData = data.map(item => item['销量'])
const profitData = data.map(item => null)
const option = {
backgroundColor: 'transparent',
grid: {
@@ -582,7 +603,7 @@ export default {
textStyle: {
color: '#fff'
},
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}'
formatter: '{b}<br/>{a0}{c0}万元<br/>{a1}{c1}万元'
},
xAxis: {
type: 'category',
@@ -649,12 +670,17 @@ export default {
this.charts.bar = chart
},
initLineChart() {
async initLineChart() {
const chart = echarts.init(this.$refs.lineChart)
const dates = ['2019/07/01', '2019/07/02', '2019/07/03', '2019/07/04', '2019/07/05', '2019/07/06', '2019/07/07', '2019/07/08', '2019/07/09', '2019/07/10']
const salesData = [1, 3350, 3280, 3420, 3380, 3500, 3450, 3520, 3480, 3550]
const profitData = [4, 2950, 2880, 3020, 2980, 3100, 3050, 3120, 3080, 3150]
const params={"chartProperties":{"毛利":"line","销售额":"bar","客户名称":"xAxis"},"setCode":"xsfx_khjg","chartType":"widget-barlinechart","contextData":{"reportCode":"salesAnalysis2026"}}
const {code,data} = await getData(params)
if(code != 200){
console.error('[Viewer] 获取大屏数据失败:', code);
return;
}
const salesData = data.map(item => item['销售额'])
const dates = data.map(item => item['客户名称'])
const profitData = data.map(item => item['毛利'])
const option = {
backgroundColor: 'transparent',
grid: {
@@ -664,21 +690,46 @@ export default {
bottom: '15%',
containLabel: true
},
graphic: {
type: 'text',
left: '10px',
top: '10px',
style: {
text: '单位:万元',
fontSize: 12,
fill: '#fff',
fontFamily: 'Microsoft YaHei'
}
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0,0,0,0.7)',
borderColor: 'rgba(255,255,255,0.2)',
confine: true,
textStyle: {
color: '#fff'
},
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}'
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}'
},
xAxis: {
type: 'category',
data: dates,
axisLine: { lineStyle: { color: 'rgba(107, 140, 174, 0.3)' } },
axisTick: { show: false },
axisLabel: { color: '#fff', fontSize: 12 }
axisLabel: {
color: '#fff',
hideOverlap: false,
interval: 0,
fontSize: 12,
margin: 8,
// 👇 核心:超出自动省略 + 鼠标悬浮显示完整
formatter: function (value) {
if (value.length > 5) {
return value.slice(0,5) + '...';
}
return value;
}
},
},
legend: {
top: '10px',
@@ -743,17 +794,23 @@ export default {
this.charts.line = chart
},
initProductBarChart() {
async initProductBarChart() {
const chart = echarts.init(this.$refs.productBarChart)
const products = ['胶囊', '片剂', '针', '14', '4', '粉剂', '2#', '4#', '8#', '9#', '10#']
const values = [50, 80, 45, 120, 90, 150, 200, 280, 320, 380, 520]
const params={"chartProperties":{"毛利":"line","销售额":"bar","货品名称":"xAxis"},"setCode":"chan_ping_fen_xi","chartType":"widget-barlinechart","contextData":{"month":"1","year":"2026","pageSize":"8","currentPage":"1","reportCode":"salesAnalysis2026"}}
const {code,data} = await getData(params)
if(code != 200){
console.error('[Viewer] 获取大屏数据失败:', code);
return;
}
const salesData = data.map(item => item['销售额'])
const dates = data.map(item => item['货品名称'])
const profitData = data.map(item => item['毛利'])
const option = {
backgroundColor: 'transparent',
grid: {
left: '20px',
right: '10px',
top: '20px',
top: '40px',
bottom: '0',
containLabel: true
},
@@ -764,14 +821,49 @@ export default {
textStyle: {
color: '#fff'
},
formatter: '{b}<br/>{a0}{c0}'
formatter: '{b}<br/>{a0}{c0}万<br/>{a1}{c1}万'
},
graphic: {
type: 'text',
left: '10px',
top: '10px',
style: {
text: '单位:万元',
fontSize: 12,
fill: '#fff',
fontFamily: 'Microsoft YaHei'
}
},
legend: {
top: '10px',
left: 'center',
itemWidth: 8,
itemHeight: 8,
textStyle: {
color: '#fff',
fontSize: 12
},
data: ['销售额', '毛利']
},
xAxis: {
type: 'category',
data: products,
data: dates,
axisLine: { lineStyle: { color: 'rgba(107, 140, 174, 0.3)' } },
axisTick: { show: false },
axisLabel: { color: '#fff', fontSize: 12 }
axisLabel: {
color: '#fff',
hideOverlap: false,
interval: 0,
fontSize: 12,
margin: 8,
// 👇 核心:超出自动省略 + 鼠标悬浮显示完整
formatter: function (value) {
if (value.length > 5) {
return value.slice(0,5) + '...';
}
return value;
}
}
},
yAxis: {
type: 'value',
@@ -783,11 +875,12 @@ export default {
}
},
series: [{
type: 'bar',
name: '销售',
name: '销售',
stack: 'a',
data: values,
data: salesData,
itemStyle: {
color: '#1890ff',
borderRadius: [2, 2, 0, 0]
@@ -796,8 +889,8 @@ export default {
},
{
type: 'line',
name: '销售量',
data: [null,null,null, 120, 90, 150, 200, 280, 320, 380, 520],
name: '毛利',
data: profitData,
itemStyle: {
color: '#C93536',
},
@@ -812,21 +905,47 @@ export default {
this.charts.productBar = chart
},
initProductLineChart() {
async initProductLineChart() {
const chart = echarts.init(this.$refs.productLineChart)
const hours = ['0','1','2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '18', '24']
const data1 = [20, 45, 65, 80, 95, 85, 70, 55, 45, 50, 60, 75, 85, 90, 88, 80, 70, 60, 50, 45, 40, 35, 30, 25]
const data2 = [15, 30, 45, 55, 70, 65, 55, 45, 40, 42, 50, 62, 72, 78, 75, 68, 58, 48, 42, 38, 35, 32, 28, 22]
const params={"chartProperties":{"毛利":"line","销售额":"bar","货品名称":"xAxis"},"setCode":"chan_ping_fen_xi","chartType":"widget-barlinechart","contextData":{"month":"1","year":"2026","pageSize":"8","currentPage":"1","reportCode":"salesAnalysis2026"}}
const {code,data} = await getData(params)
if(code != 200){
console.error('[Viewer] 获取大屏数据失败:', code);
return;
}
const data1 = data.map(item => item['销量'])
const hours = data.map(item => item['货品名称'])
const data2 = data.map(item => item['增长率'])
const option = {
backgroundColor: 'transparent',
grid: {
left: '10px',
right: '10px',
top: '30px',
top: '40px',
bottom: '0',
containLabel: true
},
graphic: [{
type: 'text',
left: '10px',
top: '10px',
style: {
text: '单位:万',
fontSize: 12,
fill: '#fff',
fontFamily: 'Microsoft YaHei'
}
},{
type: 'text',
right: '15px',
top: '10px',
style: {
text: '单位:%',
fontSize: 12,
fill: '#fff',
fontFamily: 'Microsoft YaHei'
}
}],
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0,0,0,0.7)',
@@ -834,24 +953,67 @@ export default {
textStyle: {
color: '#fff'
},
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}'
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}%'
},
legend: {
top: '10px',
left: 'center',
itemWidth: 8,
itemHeight: 8,
textStyle: {
color: '#fff',
fontSize: 12
},
data: ['销量', '增长率']
},
xAxis: {
type: 'category',
data: hours,
axisLine: { lineStyle: { color: 'rgba(107, 140, 174, 0.3)' } },
axisTick: { show: false },
axisLabel: { color: '#fff', fontSize: 12 }
},
yAxis: {
type: 'value',
show: false
axisLabel: {
color: '#fff',
hideOverlap: false,
interval: 0,
fontSize: 12,
margin: 8,
// 👇 核心:超出自动省略 + 鼠标悬浮显示完整
formatter: function (value) {
if (value.length > 5) {
return value.slice(0,5) + '...';
}
return value;
}
}
},
yAxis: [
{
type: 'value',
position: 'left',
axisLine: { show: false },
axisTick: { show: false },
splitLine: { show: false },
axisLabel: {
color: '#fff'
}
},
{
type: 'value',
position: 'right',
axisLine: { show: false },
axisTick: { show: false },
splitLine: { show: false },
axisLabel: {
color: '#fff'
}
}
],
series: [
{
type: 'line',
name: '销售额',
name: '销',
data: data1,
yAxisIndex: 0,
itemStyle: { color: '#1890ff' },
lineStyle: { width: 2 },
areaStyle: {
@@ -868,8 +1030,9 @@ export default {
},
{
type: 'line',
name: '销售量',
name: '增长率',
data: data2,
yAxisIndex: 1,
itemStyle: { color: '#ff4d4f' },
lineStyle: { width: 2 },
areaStyle: {
@@ -890,18 +1053,76 @@ export default {
this.charts.productLine = chart
},
initTrendChart() {
async initTrendChart() {
const chart = echarts.init(this.$refs.trendChart)
const days = ['1', '2', '3', '4', '5', '6', '7']
const data1 = [350, 200, 150, 100, 450, 200, 150]
const data2 = [200, 220, 180, 100, 250, 200, 125]
const params={"chartProperties":{"毛利":"line","销售额":"bar","客户名称":"xAxis"},"setCode":"xsfx_khjg","chartType":"widget-barlinechart","contextData":{"reportCode":"salesAnalysis2026"}}
const {code,data} = await getData(params)
if(code != 200){
console.error('[Viewer] 获取大屏数据失败:', code);
return;
}
const data1 = data.map(item => item['销量'])
const days = data.map(item => item['客户名称'])
const data2 = data.map(item => item['增长率_百分比'])
const option = {
backgroundColor: 'transparent',
graphic: [{
type: 'text',
left: '10px',
top: '10px',
style: {
text: '单位:万',
fontSize: 12,
fill: '#fff',
fontFamily: 'Microsoft YaHei'
}
},{
type: 'text',
right: '15px',
top: '10px',
style: {
text: '单位:%',
fontSize: 12,
fill: '#fff',
fontFamily: 'Microsoft YaHei'
}
}],
legend: {
top: '10px',
left: 'center',
itemWidth: 8,
itemHeight: 8,
textStyle: {
color: '#fff',
fontSize: 12
},
data: ['销量', '增长率']
},
yAxis: [
{
type: 'value',
axisLine: { lineStyle: { color: 'rgba(107, 140, 174, 0.3)' } },
axisLabel: { color: '#fff', fontSize: 12 },
splitLine: {
show: true, // 显示横线
lineStyle: { color: 'rgba(107, 140, 174, 0.2)' },
}
},
{
type: 'value',
position: 'right',
axisLine: { show: false },
axisTick: { show: false },
splitLine: { show: false },
axisLabel: {
color: '#fff'
}
}
],
grid: {
left: '10px',
right: '10px',
top: '20px',
top: '40px',
bottom: '10px',
containLabel: true
},
@@ -912,32 +1133,36 @@ export default {
textStyle: {
color: '#fff'
},
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}'
formatter: '{b}<br/>{a0}{c0}<br/>{a1}{c1}%'
},
xAxis: {
type: 'category',
data: days,
axisLine: { lineStyle: { color: 'rgba(107, 140, 174, 0.3)' } },
axisTick: { show: false },
axisLabel: { color: '#fff', fontSize: 12 }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: 'rgba(107, 140, 174, 0.3)' } },
axisLabel: { color: '#fff', fontSize: 12 },
splitLine: {
show: true, // 显示横线
lineStyle: { color: 'rgba(107, 140, 174, 0.2)' },
axisLabel: {
color: '#fff',
hideOverlap: false,
interval: 0,
fontSize: 12,
margin: 8,
// 👇 核心:超出自动省略 + 鼠标悬浮显示完整
formatter: function (value) {
if (value.length > 5) {
return value.slice(0,5) + '...';
}
return value;
}
}
},
series: [
{
type: 'line',
name: '销售额',
name: '销',
data: data1,
itemStyle: { color: '#20AFB1' },
lineStyle: { width: 2 },
yAxisIndex: 0,
areaStyle: {
color: {
type: 'linear',
@@ -953,10 +1178,11 @@ export default {
},
{
type: 'line',
name: '销售量',
name: '增长率',
data: data2,
itemStyle: { color: '#ff9f43' },
lineStyle: { width: 2 },
yAxisIndex: 1,
areaStyle: {
color: {
type: 'linear',
@@ -980,6 +1206,7 @@ export default {
</script>
<style lang="scss" scoped>
.sales-dashboard {
width: 100%;
height: 100%;
@@ -1222,15 +1449,46 @@ export default {
.form-dots .dot.active {
background: #1890ff;
box-shadow: 0 0 3px 3px rgba(24,144,255, 0.4) !important;
box-shadow: 0 0 3px 3px rgba(24,144,255, 0.4) ;
animation: breathBlue 1s infinite alternate;
}
.form-dots .dot:nth-of-type(1).active {
background: #E23C62;
box-shadow: 0 0 3px 3px rgba(226, 60, 98, 0.4) !important;
box-shadow: 0 0 3px 3px rgba(226, 60, 98, 0.4) ;
animation: breathRed 1s infinite alternate;
}
.form-dots .dot:nth-of-type(3).active {
background: #F5B500;
box-shadow: 0 0 3px 3px rgba(245,181,0, 0.4) !important;
box-shadow: 0 0 3px 3px rgba(245,181,0, 0.4);
animation: breathYellow 1s infinite alternate;
}
@keyframes breathBlue {
0% {
box-shadow: 0 0 2px 2px rgba(24,144,255, 0.2);
}
100% {
box-shadow: 0 0 3px 3px rgba(24,144,255, 0.6);
}
}
/* 红色呼吸动画 */
@keyframes breathRed {
0% {
box-shadow: 0 0 2px 2px rgba(226, 60, 98, 0.2);
}
100% {
box-shadow: 0 0 3px 3px rgba(226, 60, 98, 0.6);
}
}
/* 黄色呼吸动画 */
@keyframes breathYellow {
0% {
box-shadow: 0 0 2px 2px rgba(245,181,0, 0.2);
}
100% {
box-shadow: 0 0 3px 3px rgba(245,181,0, 0.6);
}
}
.form-value {
font-size: 20px;

View File

@@ -4,7 +4,7 @@
<header class="header">
<div class="logo-section">
<div class="logo-icon"></div>
<!-- <div class="logo-icon"></div> -->
<div class="title-text">
<h1 class="main-title">国瑞药业工业互联网</h1>
<!-- <span class="sub-title">Energy consumption monitoring platform-visualization of carbon peak indicatorsm</span> -->
@@ -952,7 +952,7 @@ export default {
yAxis: {
type: 'value',
show: true,
max: parkData[0].value+300,
// max: parkData[0].value+300,
splitLine: {
show: true,