This commit is contained in:
‘937886381’
2025-11-24 14:10:46 +08:00
parent dfa4ff3f54
commit 694beb5851
54 changed files with 1612 additions and 2290 deletions

View File

@@ -43,3 +43,20 @@ export function getAccountSumaryPage(data) {
params: data,
});
}
export function getProfitImpactList(data) {
return request({
url: "/lb/cost-analysis/profitImpactList",
method: "post",
data: data,
});
}
export function getSalesRevenueData(data) {
return request({
url: "lb/sales-revenue/getData",
method: "post",
data: data,
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 680 KiB

View File

@@ -143,12 +143,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {

View File

@@ -1,6 +1,6 @@
<template>
<div style="">
<Container name="利润主要影响因素" icon="cockpitItemIcon" size="profitMiddleBasic" topSize="KFAPTopTitle">
<Container name="利润主要影响因素·万元" icon="cockpitItemIcon" size="profitMiddleBasic" topSize="KFAPTopTitle">
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
<div class="left" style="width: 382px;">
<top-item :itemList="targetItemList" />

View File

@@ -109,8 +109,8 @@ export default {
lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -130,8 +130,8 @@ export default {
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
borderColor: '#fff',
borderWidth: 1
//
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -154,8 +154,8 @@ export default {
lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -175,8 +175,8 @@ export default {
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -199,8 +199,8 @@ export default {
lineStyle: { color: 'rgba(91, 230, 190, 1)', width: 2 },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -220,8 +220,8 @@ export default {
lineStyle: { color: 'rgba(255, 132, 0, 1)', width: 2 },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,

View File

@@ -63,6 +63,7 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
@@ -83,6 +84,7 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
@@ -106,11 +108,12 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -126,11 +129,12 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -149,11 +153,12 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -169,11 +174,12 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -192,11 +198,12 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(91, 230, 190, 1)' },
itemStyle: {
color: 'rgba(91, 230, 190, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,
@@ -212,11 +219,12 @@ export default {
type: 'line',
stack: 'Total',
symbol: 'circle',
symbolSize: 6,
lineStyle: { color: 'rgba(255, 132, 0, 1)' },
itemStyle: {
color: 'rgba(255, 132, 0, 1)',
borderColor: '#fff',
borderWidth: 1
borderWidth: 2
},
areaStyle: {
opacity: 0.3,

View File

@@ -50,12 +50,15 @@ export default {
data() {
return {
maintenanceTasks: [
{ id: 1, eqName: '研发经费入强度/%', taskName: '例行维护', monthlyActual: '85%', accumulated: '78%', status: 'done' }, // 已完成-绿色
{ id: 2, eqName: '存货/亿元', taskName: '例行维护', monthlyActual: '60%', accumulated: '65%', status: 'pending' }, // 完成-
{ id: 3, eqName: '三年以上应收款/亿元', taskName: '故障排查', monthlyActual: '100%', accumulated: '92%', status: 'done' },
{ id: 4, eqName: '非经营性资产处置到账金额/万元', taskName: '部件更换', monthlyActual: '45%', accumulated: '50%', status: 'pending' },
{ id: 4, eqName: '研发经费投入/万元', taskName: '部件更换', monthlyActual: '45%', accumulated: '50%', status: 'pending' },
{ id: 4, eqName: '经营性现金流/万元', taskName: '部件更换', monthlyActual: '45%', accumulated: '50%', status: 'pending' },
{
id: 1, eqName: '应收账款(亿元', taskName: '10', monthlyActual: '12.45', accumulated: '12.45', status: 'done' }, // 完成-绿
{ id: 2, eqName: '存货/亿元', taskName: '0.57', monthlyActual: '0.72', accumulated: '0.72', status: 'pending' }, // 未完成-橙色
{ id: 3, eqName: '三年以上应收款/亿元', taskName: '0.57', monthlyActual: '0.72', accumulated: '0.72', status: 'done' },
{ id: 4, eqName: '经营性资产处置到账金额/万元', taskName: '11000', monthlyActual: '0', accumulated: '0', status: 'pending' },
{ id: 1, eqName: '研发经费入强度/%', taskName: '3.07', monthlyActual: '2.37', accumulated: '3.14', status: 'done' }, // 已完成-绿色
{ id: 4, eqName: '研发经费投入/万元', taskName: '19500', monthlyActual: '1084', accumulated: '2797', status: 'pending' },
{ id: 4, eqName: '经营性现金流/万元', taskName: '2898', monthlyActual: '13472', accumulated: '-30490', status: 'pending' },
// { id: 2, eqName: '螺杆挤出', taskName: '例行维护', },

View File

@@ -36,7 +36,7 @@
</div>
</div>
<div class="lineBottom" style="height: 100%; width: 100%">
<operatingLineBar :chartData="chartData" style="height: 99%; width: 100%" />
<operatingLineBar :chartData="chartD" style="height: 99%; width: 100%" />
</div>
</div>
</template>
@@ -48,18 +48,31 @@ import * as echarts from 'echarts';
export default {
name: "Container",
components: { operatingLineBar },
props: ["name", "size", "icon"],
props: ["chartData"],
data() {
return {
activeButton: 0,
};
},
computed: {
currentDataSource() {
console.log('yyyy',this.chartData);
return this.activeButton === 0 ? this.chartData.sales : this.chartData.grossMargin;
},
locations() {
console.log('this.chartData', this.chartData);
return this.activeButton === 0 ? this.chartData.salesLocations : this.chartData.grossMarginLocations;
},
// 根据按钮切换生成对应的 chartData
chartData() {
chartD() {
// 销量场景数据
const data = this.currentDataSource;
console.log(this.currentDataSource,'currentDataSource');
const salesData = {
allPlaceNames: ['桐城', '合肥', '宜兴', '漳州', '自贡', '洛阳'], // x轴刻度
allPlaceNames: this.locations,
series: [
// 1. 完成率(折线图)
{
@@ -83,7 +96,7 @@ export default {
{ offset: 1, color: 'rgba(40, 138, 255, 0)' }
])
},
data: [104, 96.7, 107.3, 97.1, 107.7, 93.8], // 完成率(%
data: data.rates, // 完成率(%
symbol: 'circle',
symbolSize: 6
},
@@ -105,7 +118,7 @@ export default {
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: [50, 60, 55, 70, 65, 80] // 目标销量(万元)
data: data.targets // 目标销量(万元)
},
// 3. 实际(柱状图,含达标状态)
{
@@ -116,7 +129,7 @@ export default {
itemStyle: {
color: (params) => {
// 达标状态1=达标绿色0=未达标(橙色)
const safeFlag = [1, 0, 1, 0, 1, 0];
const safeFlag = data.flags;
const currentFlag = safeFlag[params.dataIndex] || 0;
return currentFlag === 1
? {
@@ -139,14 +152,13 @@ export default {
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: [52, 58, 59, 68, 70, 75] // 实际销量(万元)
data: data.reals // 实际销量(万元)
}
]
};
// 毛利率场景数据
const grossProfitData = {
allPlaceNames: ['1月', '2月', '3月', '4月', '5月', '6月'],
series: [
// 1. 完成率(折线图)
{

View File

@@ -111,15 +111,16 @@ export default {
// 左侧Y轴营业收入、成本单位万元
{
type: 'value',
splitNumber: 4,
name: '万元',
nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
align: 'right'
},
min: 0,
max: (value) => Math.ceil((value.max || 0) * 1.1),
scale: false,
// min: 0,
// max: (value) => Math.ceil((value.max || 0) * 1.1),
scale: true,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
@@ -138,8 +139,10 @@ export default {
fontSize: 12,
align: 'left'
},
min: 0,
max: 100,
// min: 0,
// max: 100,
scale:true,
splitNumber: 4,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',

View File

@@ -117,9 +117,8 @@ export default {
fontSize: 12,
align: 'right'
},
min: 0,
max: (value) => Math.ceil((value.max || 0) * 1.1),
scale: false,
scale: true,
splitNumber: 4,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',

View File

@@ -16,13 +16,11 @@ export default {
chartData: {
type: Object,
default: () => ({
series: [],
allPlaceNames: []
}),
// 校验数据格式
validator: (value) => {
return Array.isArray(value.series) && Array.isArray(value.allPlaceNames);
}
// validator: (value) => {
// return Array.isArray(value.series) && Array.isArray(value.allPlaceNames);
// }
}
},
mounted() {
@@ -37,7 +35,6 @@ export default {
chartData: {
handler() {
console.log(this.chartData,'chartData');
this.updateChart();
},
deep: true,
@@ -58,6 +55,7 @@ export default {
this.myChart = echarts.init(chartDom);
const { allPlaceNames, series } = this.chartData || {};
console.log('chartData', this.chartData);
// 处理空数据
const xData = allPlaceNames || [];
@@ -117,9 +115,8 @@ export default {
fontSize: 12,
align: 'right'
},
min: 0,
max: (value) => Math.ceil((value.max || 0) * 1.1),
scale: false,
scale: true,
splitNumber: 4,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
@@ -128,7 +125,6 @@ export default {
},
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
},
// 右侧Y轴利润占比百分比
{
@@ -148,7 +144,8 @@ export default {
},
splitLine: { show: false },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
// scale: true,
splitNumber: 4,
}
],
series: chartSeries // 直接使用父组件传递的 series

View File

@@ -3,10 +3,9 @@
<Container name="趋势图" icon="cockpitItemIcon" size="operatingLarge" topSize="large">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
<div class="bottom"
style="height: 380px; display: flex; width: 100%;background-color: rgba(249, 252, 255, 1);">
<div class="bottom" style="height: 380px; display: flex; width: 100%;background-color: rgba(249, 252, 255, 1);">
<!-- <top-item /> -->
<coreBottomBar />
<coreBottomBar :chartData="chartData" />
</div>
</div>
@@ -15,157 +14,124 @@
</template>
<script>
import Container from './container.vue'
// import * as echarts from 'echarts'
import coreBottomBar from './operatingBar.vue'
export default {
name: 'ProductionStatus',
components: { Container, coreBottomBar },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
salesTrendMap: {
type: Object,
default: () => ({})
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
grossMarginTrendMap: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null
chartData: null // 初始化 chartData 为 null
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
grossMarginTrendMap: {
handler() {
this.processChartData();
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
immediate: true,
deep: true
},
salesTrendMap: {
handler() {
this.processChartData();
},
immediate: true,
deep: true
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
/**
* 核心处理函数:在所有数据都准备好后,才组装 chartData
*/
processChartData() {
// 关键改动:增加数据有效性检查
// 检查 salesTrendMap 是否有实际数据(不只是空对象)
const isSalesDataReady = Object.keys(this.salesTrendMap).length > 0;
// 检查 grossMarginTrendMap 是否有实际数据
const isGrossMarginDataReady = Object.keys(this.grossMarginTrendMap).length > 0;
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
// 如果任一数据未准备好,则不更新 chartData或传递一个加载中的状态
// 你可以根据业务需求调整这里的逻辑,比如:
// 1. 等待两者都准备好
// 2. 只要有一个准备好了就更新,但确保另一个有合理的默认值
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
// --- 方案一:等待两者都准备好 ---
// if (!isSalesDataReady || !isGrossMarginDataReady) {
// console.log('数据尚未全部准备好,暂不更新图表');
// this.chartData = {
// grossMarginLocations: [],
// salesLocations: [],
// grossMargin: { rates: [], reals: [], targets: [], flags: [] },
// sales: { rates: [], reals: [], targets: [], flags: [] },
// };
// return;
// }
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
}
// --- 方案二 (推荐):有什么数据就显示什么,没有的就显示空 ---
// 这种方式更友好,用户可以先看到部分数据
const grossMarginLocations = isGrossMarginDataReady ? Object.keys(this.grossMarginTrendMap) : [];
const salesLocations = isSalesDataReady ? Object.keys(this.salesTrendMap) : [];
this.chart.setOption(option)
const processedGrossMarginData = isGrossMarginDataReady
? this.processSingleDataset(grossMarginLocations, this.grossMarginTrendMap)
: { rates: [], reals: [], targets: [], flags: [] };
const processedSalesData = isSalesDataReady
? this.processSingleDataset(salesLocations, this.salesTrendMap)
: { rates: [], reals: [], targets: [], flags: [] };
// 3. 组装最终的 chartData 对象
this.chartData = {
grossMarginLocations: grossMarginLocations,
salesLocations: salesLocations,
grossMargin: processedGrossMarginData,
sales: processedSalesData
};
console.log('chartData 已更新:', this.chartData);
},
/**
* 通用数据处理函数(纯函数)
* @param {Array} locations - 某个指标的地点数组
* @param {Object} dataMap - 该指标的原始数据映射
* @returns {Object} - 格式化后的数据对象
*/
processSingleDataset(locations, dataMap) {
const rates = [];
const reals = [];
const targets = [];
const flags = [];
locations.forEach(location => {
const data = dataMap[location] || {};
// 优化:处理 data.rate 为 null/undefined 的情况
const rate = data.rate !== null && data.rate !== undefined ? Math.round(data.rate * 100) : 0;
rates.push(rate);
reals.push(data.real ?? 0); // 使用空值合并运算符
targets.push(data.target ?? 0);
// 优化:更清晰的逻辑
if (data.target === 0) {
flags.push(1); // 如果目标为0默认达标
} else {
flags.push(rate >= 100 ? 1 : 0);
}
});
return { rates, reals, targets, flags };
}
}
}

View File

@@ -5,7 +5,7 @@
<div class="kpi-content" style="padding: 14px 14px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
<div class="top" style="display: flex; width: 100%;">
<top-item :height="367" :itemList="parentItemList" />
<top-item v-if="saleData" :height="367" :itemList="formattedParentItemList" />
</div>
<div class="bottom"
style="display: flex; width: 100%;margin-top: 8px;background-color: rgba(249, 252, 255, 1);">
@@ -27,14 +27,10 @@ export default {
components: { Container, topItem },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
saleData: { // 接收父组件传递的设备数据数组
type: Object,
default: () => ({})
}
default: () => {} // 默认空数组,避免报错
},
},
data() {
return {
@@ -42,57 +38,57 @@ export default {
parentItemList: [
{
name: "利润总额",
targetValue: 50,
value: 58,
proportion: 116,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 1 // 实际超目标,达标
},
{
name: "毛利率",
targetValue: 30,
value: 28.5,
proportion: 95,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 0 // 未达30%目标,不达标
completed: 1 // 未达30%目标,不达标
},
{
name: "单价",
targetValue: 12,
value: 12.5,
proportion: 104.2,
targetValue: 0,
value: 0,
proportion: 0,
route: 'cost/cost',
completed: 1 // 单价达标
},
{
name: "净价",
targetValue: 9,
value: 8.8,
proportion: 97.8,
targetValue: 0,
value: 0,
proportion: 0,
route: 'cost/cost',
completed: 0 // 未达目标,不达标
completed: 1 // 未达目标,不达标
},
{
name: "销量",
targetValue: 100,
value: 120,
proportion: 120,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 1 // 销量超额达标
},
{
name: "双镀面板",
targetValue: 30,
value: 29,
proportion: 96.7,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 0 // 略低目标,不达标
completed: 1 // 略低目标,不达标
},
{
name: "溢价产品销量",
targetValue: 15,
value: 18,
proportion: 120,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 1 // 超额达标
}
@@ -100,135 +96,59 @@ export default {
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
computed: {
formattedParentItemList() {
// --- 新增判断 ---
// 如果 saleData 不存在、为 null或者是不包含任何属性的空对象则返回原始的 parentItemList
if (!this.saleData || Object.keys(this.saleData).length === 0) {
return this.parentItemList;
}
// --- 判断结束 ---
// 定义一个名称到键的映射表,方便查找
const nameToKeyMap = {
"利润总额": "totalProfit",
"毛利率": "grossMargin",
"单价": "unitPrice",
"净价": "netPrice",
"销量": "sales",
"双镀面板": "panel",
"溢价产品销量": "premiumProduct"
};
// 遍历原始的 parentItemList
return this.parentItemList.map(item => {
// 根据当前 item 的 name 找到 SaleData 中对应的键
const key = nameToKeyMap[item.name];
// 如果找到了对应的键,并且 saleItem 存在,就从 SaleData 中获取数据
if (key && this.saleData[key]) {
const saleItem = this.saleData[key];
return {
...item,
value: saleItem.real,
targetValue: saleItem.target,
// proportion: saleItem.rate !== null && saleItem.rate !== undefined
// ? Math.round(saleItem.rate * 100)
// : 0,
// 直接使用处理好的 rate
proportion: saleItem.rate,
// 根据完成率判断是否达标 (假设 >=100% 为达标)
completed: saleItem.rate >= 1 ? 1 : 0,
};
}
// 如果没有找到对应的数据,则返回原始 item
return item;
});
},
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
}
this.chart.setOption(option)
}
}
}
</script>
@@ -391,14 +311,4 @@ export default {
</style>
<style>
/* 全局 tooltip 样式(不使用 scoped确保生效 */
.production-status-chart-tooltip {
background: #0a2b4f77 !important;
border: none !important;
backdrop-filter: blur(12px);
}
.production-status-chart-tooltip * {
color: #fff !important;
}
</style>

View File

@@ -17,21 +17,35 @@ export default {
// // 验证ref 名不能为空,确保有效
// return value.trim() !== '';
// }
}
},
pieData: {
type: Object,
default: () => { } // 默认空数组,避免报错
},
},
components: {},
data() {
return {};
},
computed: {},
watch: {
// 监听 pieData 变化,只要数据变了,就更新图表
pieData: {
handler() {
this.initData(); // 直接调用更新,无需判断 myChart 是否存在
},
deep: true,
immediate: true // 初始化时立即执行
},
},
mounted() {
this.$nextTick(() => {
this.initData();
this.initChart(); // 只负责初始化图表实例
});
},
methods: {
initData() {
// 2. 动态获取 DOM通过 props 中的 chartRef 拿到对应的 ref 元素
console.log(this.pieData,'this.pieData.value');
const chartDom = this.$refs[this.chartRef];
if (!chartDom) {
console.error(`图表容器未找到!请确认父组件传递的 chartRef 为 "${this.chartRef}"`);
@@ -94,7 +108,7 @@ export default {
labelLine: {
show: true,
length: 0,
length2: 30,
length2: 10,
lineStyle: {
color: (params) => customColors[params.dataIndex]
}
@@ -104,7 +118,7 @@ export default {
},
data: [
{
value: 1048, name: '单镀面板',
value: this.pieData?.value || 0, name: '单镀面板',
label: {
normal: {
align: 'left',
@@ -133,7 +147,9 @@ export default {
}
},
labelLine: {
lineStyle: { color: 'rgba(39, 96, 255, 1)' }
lineStyle: { color: 'rgba(39, 96, 255, 1)' },
length: 10,
length2: 20,
},
itemStyle: { color: 'rgba(39, 96, 255, 1)' }
},
@@ -168,8 +184,8 @@ export default {
},
labelLine: {
length: 0,
length2: 50,
lineStyle: { color: 'rgba(40, 138, 255, 1)' }
length2: 10,
lineStyle: { color: 'rgba(40, 138, 255, 1)' },
},
itemStyle: { color: 'rgba(40, 138, 255, 1)' }
},
@@ -203,7 +219,9 @@ export default {
}
},
labelLine: {
lineStyle: { color: 'rgba(118, 218, 190, 1)' }
lineStyle: { color: 'rgba(118, 218, 190, 1)' },
length: 0,
length2: 10,
},
itemStyle: { color: 'rgba(118, 218, 190, 1)' }
},
@@ -237,7 +255,9 @@ export default {
}
},
labelLine: {
lineStyle: { color: 'rgba(255, 206, 106, 1)' }
lineStyle: { color: 'rgba(255, 206, 106, 1)' },
length: 10,
length2: 10,
},
itemStyle: { color: 'rgba(255, 206, 106, 1)' }
}

View File

@@ -5,7 +5,7 @@
<div class="kpi-content" style="padding: 14px 16px 8px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
<div class="top" style="display: flex; width: 100%;">
<top-item :itemList="parentItemList" />
<top-item :itemList="formattedPremiumProductList" />
</div>
</div>
<div class="bottom-content" style="display: flex;flex-direction: column; width: 100%;">
@@ -28,10 +28,10 @@
</div>
<div class="pie" style="display: flex;gap: 8px;margin-top: 68px;padding: 0 16px;">
<div class="month-pie" style="height: 212px;width: 382px;background: #F9FCFF;">
<pieChart :chartRef=" 'monthChart' " />
<pieChart :pieData="monthPieData" :chartRef=" 'monthChart' " />
</div>
<div class="-pie" style="height: 212px;width: 382px;background: #F9FCFF;">
<pieChartTwo :chartRef="'yearChart'" />
<pieChartTwo :pieData="yearPieData" :chartRef="'yearChart'" />
</div>
</div>
@@ -54,11 +54,11 @@ export default {
components: { Container, topItem, coreBottomBar, pieChart, pieChartTwo },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
premiumProduct: { // 接收父组件传递的设备数据数组
type: Object,
default: () => {} // 默认空数组,避免报错
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
salesProportion: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
type: Object,
default: () => ({})
}
@@ -66,20 +66,22 @@ export default {
data() {
return {
chart: null,
monthPieData: {},
yearPieData:{},
parentItemList: [
{
name: "月度",
targetValue: 80,
value: 76,
proportion: 95,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 0 // 未达目标值,不达标
completed: 1 // 未达目标值,不达标
},
{
name: "年度",
targetValue: 900,
value: 920,
proportion: 102.2,
targetValue: 0,
value: 0,
proportion: 0,
route: 'profitAnalysis',
completed: 1 // 超出目标值,达标
}
@@ -87,134 +89,68 @@ export default {
}
},
watch: {
productionOverviewVo: {
salesProportion: {
handler(newValue, oldValue) {
this.updateChart()
console.log('salesProportion',newValue);
this.getPieData()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
computed: {
formattedPremiumProductList() {
const premiumProductData = this.premiumProduct || {};
const nameToKeyMap = {
"月度": "month",
"年度": "year"
};
return this.parentItemList.map(item => {
const key = nameToKeyMap[item.name];
if (key && premiumProductData[key]) {
const periodData = premiumProductData[key];
let completed = 0;
// 新增判断三个值是否都为0
const allZeros = periodData.real === 0 &&
periodData.target === 0 &&
periodData.rate === 0;
if (allZeros) {
completed = 1;
} else if (periodData.rate !== null && periodData.rate !== undefined) {
completed = periodData.rate >= 1 ? 1 : 0;
}
return {
...item,
value: periodData.real,
targetValue: periodData.target,
proportion: periodData.rate !== null && periodData.rate !== undefined
? Math.round(periodData.rate * 100)
: 0,
completed: completed,
};
}
return item;
});
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
getPieData() {
this.monthPieData = this.salesProportion ? this.salesProportion.month : {}
this.yearPieData = this.salesProportion ? this.salesProportion.year : {}
console.log('this.monthPieData', this.monthPieData, this.yearPieData);
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
}
this.chart.setOption(option)
}
}
}
@@ -392,16 +328,3 @@ export default {
}
</style>
<style>
/* 全局 tooltip 样式(不使用 scoped确保生效 */
.production-status-chart-tooltip {
background: #0a2b4f77 !important;
border: none !important;
backdrop-filter: blur(12px);
}
.production-status-chart-tooltip * {
color: #fff !important;
}
</style>

View File

@@ -118,8 +118,20 @@ export default {
yAxisIndex: 0,
barWidth: 18,
itemStyle: {
color: '#2889FF',
borderRadius: [4, 4, 0, 0]
// 移除多余的 normal 层级,直接配置 color 渐变
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(130, 204, 255, 1)' },
{ offset: 1, color: 'rgba(75, 157, 255, 1)' }
]
},
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: targetData.map(item => item.targetValue)
},

View File

@@ -1,6 +1,6 @@
<template>
<div style="flex: 1">
<Container name="利润数据总览" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
<Container name="利润数据总览·万元" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->

View File

@@ -151,9 +151,8 @@ export default {
fontSize: 12,
align: 'right'
},
min: 0,
max: (value) => value.max > 0 ? Math.ceil(value.max * 1.1) : 10,
scale: false,
scale: true,
splitNumber: 4,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
@@ -162,7 +161,6 @@ export default {
},
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
},
{
type: 'value',
@@ -171,8 +169,8 @@ export default {
fontSize: 12,
align: 'left'
},
min: 0,
max: 100,
// min: 0,
// max: 100,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',

View File

@@ -1,6 +1,6 @@
<template>
<div style="flex: 1">
<Container name="产销数据总览" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
<Container name="产销数据总览·万㎡" icon="cockpitItemIcon" size="profitTopBasic" topSize="middle">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->

View File

@@ -9,14 +9,14 @@
<div class="visual-base-table-container">
<el-table :max-height="maxHeight" ref="scroll_Table" @mouseenter.native="autoScroll(true)"
@mouseleave.native="autoScroll(false)" v-loading="isLoading"
:header-cell-style="{ background: 'rgba(218, 226, 237, 1)', color: 'rgba(0, 0, 0, .6)',padding:'3px 2px'}" :row-style="setRowStyle"
:data="renderData" border style="width: 100%; background: transparent">
:header-cell-style="{ background: 'rgba(218, 226, 237, 1)', color: 'rgba(0, 0, 0, .6)', padding: '3px 2px' }"
:row-style="setRowStyle" :data="renderData" border style="width: 100%; background: transparent">
<el-table-column v-if="page && limit && showIndex" prop="_pageIndex" label="序号" :width="70" align="center" />
<el-table-column v-for="item in renderTableHeadList" :key="item.prop" :show-overflow-tooltip="showOverflow"
v-bind="item">
<template slot-scope="scope">
<component :is="item.subcomponent" v-if="item.subcomponent" :inject-data="{...scope.row, ...item}"
<component :is="item.subcomponent" v-if="item.subcomponent" :inject-data="{ ...scope.row, ...item }"
@emitData="emitData" />
<span v-else>{{ scope.row[item.prop] | commonFilter(item.filter) }}</span>
@@ -39,7 +39,7 @@ export default {
maxHeight: {
type: [Number, String], // 支持数字如300或字符串如'300px'
required: false,
default: 230 // 原固定值,作为默认 fallback
default: 200 // 原固定值,作为默认 fallback
},
tableData: {
type: Array,
@@ -130,7 +130,7 @@ export default {
if (divData.scrollTop + divData.clientHeight >= divData.scrollHeight - 1) {
// 滚动到底部后,重置到顶部(延迟一点更自然)
// setTimeout(() => {
divData.scrollTop = 0
divData.scrollTop = 0
// }, 2000); // 停顿500ms后再从头滚动
}
}, 200) // 滚动速度(数值越小越快)
@@ -144,19 +144,19 @@ export default {
return {
background: '#F9FCFF',
color: 'rgba(87, 87, 87, 1)',
height: 35 + 'px',
height: 35 + 'px',
lineHeight: 26 + 'px',
padding: 0,
fontSize: 12 + 'px'
fontSize: 12 + 'px'
}
} else {
return {
background: 'rgba(239, 243, 248, 1)',
color: 'rgba(87, 87, 87, 1)',
height: 35 + 'px',
lineHeight: 26 + 'px',
height: 35 + 'px',
lineHeight: 26 + 'px',
padding: 0,
fontSize: 12 + 'px'
fontSize: 12 + 'px'
}
}
},
@@ -171,19 +171,25 @@ export default {
<style lang="scss" scoped>
// @import "./styles/index.scss";
.visual-base-table-container {
.el-table {
.el-table {
border: 0;
// .el-table__body-wrapper::-webkit-scrollbar-thumb {
// background-color: blue;
// border-radius: 3px;
// }
// 关键修改:隐藏滚动条但保留滚动功能
&::-webkit-scrollbar {
width: 0;
height: 0;
background: transparent;
}
// 隐藏表头的gutter
.el-table__header .el-table__cell.gutter {
display: none !important;
}
// 隐藏表头的gutter
.el-table__header .el-table__cell.gutter {
display: none !important;
}
// 表格主体内容区滚动条处理
.el-table__body-wrapper {
&::-webkit-scrollbar {
@@ -217,24 +223,31 @@ export default {
}
}
}
.el-table::before,.el-table--border::after {
.el-table::before,
.el-table--border::after {
background-color: transparent;
}
.el-table th,td{
.el-table th,
td {
border-color: rgba(221, 221, 221, 1) !important;
padding: 0;
}
.el-table tr {
background: transparent;
}
.el-table__row:hover > td {
background-color: rgba(79,114,136,0.29) !important;
}
.el-table__row--striped:hover > td {
background-color: rgba(79,114,136,0.29) !important;
.el-table__row:hover>td {
background-color: rgba(79, 114, 136, 0.29) !important;
}
.el-table__row--striped:hover>td {
background-color: rgba(79, 114, 136, 0.29) !important;
}
}
// .setting {
// text-align: right;
// padding: 15px;
@@ -246,5 +259,4 @@ export default {
// @extend .pointer;
// }
// }
</style>

View File

@@ -1,33 +1,24 @@
<template>
<div class="coreBar">
<div class="barTop">
<!-- 标题单独左对齐 -->
<!-- <div class="title">销售指标趋势</div> -->
<!-- 关键新增右侧容器包裹图例和按钮组实现整体靠右 -->
<div class="right-container">
<div class="legend">
<span class="legend-item">
<span class="legend-icon square target"></span>
目标
</span>
<!-- 给第三个第四个图例项加 close-item -->
<span class="legend-item">
<span class="legend-icon square achieved"></span>
实际
</span>
<!-- <span class="legend-item close-item">
<span class="legend-icon square unachieved"></span>
</span> -->
</div>
<!-- 按钮组改为下拉框样式仅宽度与第二个组件一致 -->
<div class="button-group">
<div class="item-button category-btn">
<span class="item-text" style="width: 88px;">类目选择</span>
</div>
<div class="dropdown-container">
<div class="item-button profit-btn active" @click.stop="isDropdownShow = !isDropdownShow">
<span class="item-text profit-text">{{ selectedProfit || '原料' }}</span>
<span class="item-text profit-text">{{ selectedProfit || '请选择' }}</span>
<span class="dropdown-arrow" :class="{ 'rotate': isDropdownShow }"></span>
</div>
<div class="dropdown-options" v-if="isDropdownShow">
@@ -41,7 +32,8 @@
</div>
</div>
<div class="lineBottom" style="height: 100%; width: 1590px">
<costBaseBarChart :yName="yName" style="height: 99%; width: 1590px" />
<!-- 传递筛选后的数据给图表组件 -->
<costBaseBarChart :yName="yName" :chartData="filteredData" style="height: 99%; width: 1590px" />
</div>
</div>
</template>
@@ -51,15 +43,40 @@ import costBaseBarChart from './costBaseBarChart.vue';
export default {
name: "Container",
components: { costBaseBarChart },
props: ['dateData','yName'],
props: ['dateData', 'yName', 'categoryData'],
data() {
return {
isDropdownShow: false,
selectedProfit: '原料', // 默认选中"原料"
profitOptions: ['原料', '其他选项1', '其他选项2'], // 可根据实际需求修改选项
selectedProfit: null, // 选中的名称初始为null
};
},
computed: {},
computed: {
// 从categoryData中提取name作为下拉选项
profitOptions() {
return this.categoryData.map(item => item.name) || [];
},
// 根据选中的名称筛选数据
filteredData() {
if (!this.selectedProfit || !this.categoryData.length) {
// 未选择时默认取第一个分类的数据(或空)
return this.categoryData[0] || {};
}
// 找到选中名称对应的分类数据
return this.categoryData.find(item => item.name === this.selectedProfit) || {};
}
},
watch: {
categoryData: {
handler() {
// 当分类数据变化时,若没有选中项则默认选中第一个
if (this.categoryData.length && !this.selectedProfit) {
this.selectedProfit = this.categoryData[0].name;
}
},
deep: true,
immediate: true
}
},
methods: {
selectProfit(item) {
this.selectedProfit = item;
@@ -82,6 +99,7 @@ export default {
</script>
<style scoped lang="scss">
/* 原有样式保持不变 */
.coreBar {
display: flex;
flex-direction: column;
@@ -95,19 +113,6 @@ export default {
gap: 16px;
width: 100%;
.title {
height: 18px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 18px;
color: #000000;
line-height: 18px;
letter-spacing: 1px;
text-align: left;
font-style: normal;
white-space: nowrap;
}
.right-container {
display: flex;
align-items: center;
@@ -138,32 +143,11 @@ export default {
display: inline-block;
}
.legend-icon.line {
width: 12px;
height: 2px;
position: relative;
&::before {
position: absolute;
content: "";
top: -2px;
left: 3px;
width: 6px;
border-radius: 50%;
height: 6px;
background-color: rgba(40, 138, 255, 1);
}
}
.legend-icon.square {
width: 8px;
height: 8px;
}
.yield {
background: rgba(40, 138, 255, 1);
}
.target {
background: #2889FF;
}
@@ -172,15 +156,6 @@ export default {
background: rgba(40, 203, 151, 1);
}
.unachieved {
background: rgba(255, 132, 0, 1);
}
.legend-item.close-item+.legend-item.close-item {
margin-left: -8px;
}
// 按钮组:完全复用第二个组件样式,仅保持原有宽度适配
.button-group {
display: flex;
position: relative;
@@ -222,7 +197,7 @@ export default {
}
.profit-btn {
width: 102px; // 保持原组件要求的宽度,其余样式与第二个组件一致
width: 102px;
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
position: relative;
@@ -264,7 +239,7 @@ export default {
top: 100%;
right: 0;
margin-top: 2px;
width: 102px; // 与按钮宽度一致
width: 102px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

View File

@@ -8,27 +8,68 @@ import * as echarts from 'echarts';
export default {
components: {},
data() {
return {};
return {
myChart: null // 保存图表实例,方便更新
};
},
props: {
yName: {
type: String,
default: () => '元/㎡'
},
chartData: {
type: Object,
default: () => { }
},
},
watch: {
chartData: {
handler() {
this.updateChart(); // 数据变化时更新图表
},
deep: true,
immediate: true
}
},
mounted() {
this.$nextTick(() => {
this.initData();
this.initChart();
});
},
methods: {
initData() {
initChart() {
const chartDom = this.$refs.cockpitEffChip;
if (!chartDom) {
console.error('图表容器未找到!');
return;
}
const myChart = echarts.init(chartDom);
this.myChart = echarts.init(chartDom);
this.updateChart(); // 初始化图表数据
// 窗口缩放适配
window.addEventListener('resize', () => {
this.myChart && this.myChart.resize();
});
// 组件销毁清理
this.$once('hook:destroyed', () => {
window.removeEventListener('resize', () => {
this.myChart && this.myChart.resize();
});
this.myChart && this.myChart.dispose();
});
},
updateChart() {
if (!this.myChart || !this.chartData.rawData || !this.chartData.timeArray) {
return; // 图表未初始化或数据不完整时不更新
}
// 从rawData中提取目标和实际数据
const targetData = this.chartData.rawData.map(item => item.target); // 目标数据数组
const actualData = this.chartData.rawData.map(item => item.value); // 实际数据数组
const xAxisData = this.chartData.timeArray; // 横坐标时间数组
const option = {
tooltip: {
trigger: 'axis',
@@ -38,26 +79,24 @@ export default {
backgroundColor: '#6a7985'
}
},
// 优化tooltip内容区分各系列含义
formatter: (params) => {
let html = `${params[0].axisValue}<br/>`;
params.forEach(item => {
// 直接使用系列名,无需映射,仅保留单位判断
html += `${item.marker} ${item.seriesName}: ${item.value}${item.seriesName === '完成率' ? '%' : '片'}<br/>`;
html += `${item.marker} ${item.seriesName}: ${item.value}${this.yName}<br/>`;
});
return html;
}
},
grid: {
top: 30,
bottom: 30, // 增大底部间距避免柱子与X轴标签重叠
bottom: 30,
right: 70,
left: 40,
left: 60,
},
xAxis: [
{
type: 'category',
boundaryGap: true, // 开启边界间隙,让柱子居中显示,不贴边
boundaryGap: true,
axisTick: { show: false },
axisLine: {
show: true,
@@ -67,13 +106,12 @@ export default {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
interval: 0,
padding: [5, 0, 0, 0] // 标签向下偏移,避免与柱子底部重叠
padding: [5, 0, 0, 0]
},
data: ['6月', '7月', '8月', '9月', '10月', '11月']
data: xAxisData // 使用timeArray作为横坐标
}
],
yAxis: [
// 左侧Y轴目标/达标/未达标(数量,单位“片”)
{
type: 'value',
name: this.yName,
@@ -82,77 +120,28 @@ export default {
fontSize: 12,
align: 'right'
},
min: 0, // 最小值设0确保柱子从X轴底部开始不超过X轴
max: (value) => Math.ceil(value.max * 1.1), // 最大值留10%余量,避免柱子顶满
scale: false, // 关闭缩放强制从0开始
// min: 0,
// max: (value) => value.max > 0 ? Math.ceil(value.max * 1.1) : 100, // 留10%余量
scale: true,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
formatter: '{value}'
formatter: `{value}`
},
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
},
// 右侧Y轴完成率百分比
// {
// type: 'value',
// // name: '%',
// nameTextStyle: {
// color: 'rgba(0, 0, 0, 0.45)',
// fontSize: 12,
// align: 'left'
// },
// min: 0,
// max: 100, // 完成率最大100%,符合业务逻辑
// axisTick: { show: false },
// axisLabel: {
// color: 'rgba(0, 0, 0, 0.45)',
// fontSize: 12,
// formatter: '{value}%'
// },
// splitLine: { show: false }, // 不重复显示分割线
// axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
// splitNumber: 4
// }
splitNumber: 3
}
],
series: [
// 1. 完成率折线图绑定右侧百分比Y轴
// {
// name: '产销率',
// type: 'line',
// yAxisIndex: 1, // 绑定右侧Y轴
// lineStyle: {
// color: 'rgba(40, 138, 255, .5)',
// width: 2 // 线条加粗,突出重点
// },
// itemStyle: {
// color: 'rgba(40, 138, 255, 1)',
// borderColor: 'rgba(40, 138, 255, 1)', // 数据点白色边框,增强辨识度
// borderWidth: 2,
// radius: 4 // 数据点圆角,更圆润
// },
// areaStyle: {
// opacity: 0.2, // 降低面积透明度,不抢柱状图视觉焦点
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: 'rgba(40, 138, 255, .9)' },
// { offset: 1, color: 'rgba(255, 132, 0, 0)' }
// ])
// },
// data: [65, 78, 52, 85, 60, 95, 72], // 完成率数据0-100
// symbol: 'circle', // 数据点为圆形
// symbolSize: 6 // 数据点大小
// },
// 2. 目标柱状图绑定左侧数量Y轴
// 目标数据柱状图
{
name: '销量',
name: '目标',
type: 'bar',
yAxisIndex: 0,
barWidth: 24,
// 关键修复label 直接放在 series 下,而非 itemStyle 内
itemStyle: {
// 移除多余的 normal 层级,直接配置 color 渐变
color: {
type: 'linear',
x: 0,
@@ -167,17 +156,15 @@ export default {
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: [200, 280, 180, 300, 220, 350]
data: targetData // 目标数据数组
},
// 3. 达标柱状图绑定左侧数量Y轴
// 实际数据柱状图
{
name: '产量',
name: '实际',
type: 'bar',
yAxisIndex: 0,
barWidth: 24,
// 关键修复label 直接放在 series 下,而非 itemStyle 内
itemStyle: {
// 移除多余的 normal 层级,直接配置 color 渐变
color: {
type: 'linear',
x: 0,
@@ -192,50 +179,12 @@ export default {
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: [130, 220, 95, 255, 132, 332] // 达标数据(小于目标)
},
// 4. 未达标柱状图绑定左侧数量Y轴
// {
// name: '未达标',
// type: 'bar',
// yAxisIndex: 0,
// barWidth: 18,
// itemStyle: {
// color: 'rgba(249, 164, 74, 1)',
// borderRadius: [4, 4, 0, 0],
// borderWidth: 0
// },
// data: [70, 60, 85, 45, 88, 18, 78] // 未达标数据(目标-达标)
// }
],
// 图例:区分各系列,点击可控制显示隐藏
// legend: {
// top: 0,
// left: 'center',
// itemWidth: 12,
// itemHeight: 8,
// textStyle: {
// color: 'rgba(0, 0, 0, 0.45)',
// fontSize: 12
// },
// data: ['完成率', '目标', '达标', '未达标']
// }
data: actualData // 实际数据数组
}
]
};
option && myChart.setOption(option);
// 窗口缩放适配
window.addEventListener('resize', () => {
myChart.resize();
});
// 组件销毁清理
this.$once('hook:destroyed', () => {
window.removeEventListener('resize', () => {
myChart.resize();
});
myChart.dispose();
});
this.myChart.setOption(option);
}
},
};

View File

@@ -260,7 +260,7 @@ export default {
.middle-line {
width: 100%;
height: 1px;
background: linear-gradient(to right, rgba(40, 203, 151, 0.3), rgba(40, 203, 151, 0.8), rgba(40, 203, 151, 0.3));
background: linear-gradient(to right, #cbcbcb rgba(255, 255, 255, 0));
}
.number {

View File

@@ -1,10 +1,10 @@
<template>
<div style="width: 100%;">
<Container name="领用明细" icon="cockpitItemIcon" size="" topSize="middle">
<Container name="领用明细" icon="cockpitItemIcon" size="productMiddleBg" topSize="middle">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style=" padding: 14px 16px; display: flex;width: 100%;">
<div class="bottom"
style="padding: 14px 16px; height: 620px; display: flex; width: 100%;;">
style="padding: 14px 16px; height: 620px; display: flex; width: 100%;background-color: #ffffff;">
<!-- <top-item /> -->
<base-table style="width: 100%;" :page="1" :limit="10" :show-index="true" :beilv="1" :tableConfig="tableProps"
:table-data="tableData" />

View File

@@ -1,10 +1,10 @@
<template>
<div style="width: 100%;">
<Container name="入账明细" icon="cockpitItemIcon" size="" topSize="middle">
<Container name="入账明细" icon="cockpitItemIcon" size="productMiddleBg" topSize="middle">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
<div class="bottom"
style="padding: 14px 16px; height: 620px; display: flex; width: 100%;">
style="padding: 14px 16px; height: 620px; display: flex; width: 100%;background-color: #ffffff;">
<!-- <top-item /> -->
<base-table style="width: 100%;" :page="1" :limit="10" :show-index="true" :beilv="1" :tableConfig="tableProps"
:table-data="tableData" />
@@ -81,7 +81,7 @@ export default {
}
</script>
<style lang='scss' scoped>
<!-- <style lang='scss' scoped>
/* 3. 核心:滚动容器样式(固定高度+溢出滚动+隐藏滚动条) */
.scroll-container {
/* 1. 固定容器高度根据页面布局调整示例300px超出则滚动 */
@@ -249,4 +249,4 @@ export default {
.production-status-chart-tooltip * {
color: #fff !important;
}
</style>
</style> -->

View File

@@ -1,7 +1,8 @@
<template>
<div class="coreBar">
<div class="lineBottom" style="height: 100%; width: 1590px">
<profitImpactLineChart :yName="yName" style="height: 99%; width: 1590px" />
<profitImpactLineChart :name="name" :seriesData="seriesData" :xData="xData" :yName="yName"
style="height: 99%; width: 1590px" />
</div>
</div>
</template>
@@ -11,12 +12,22 @@ import profitImpactLineChart from './profitImpactLineChart.vue';
export default {
name: "Container",
components: { profitImpactLineChart },
props: ['dateData','yName'],
props: {
seriesData: {
type: Array,
default: () => []
},
xData: {
type: Array,
default: () => []
},
name: {
type: String,
default: () => { }
},
},
data() {
return {
isDropdownShow: false,
selectedProfit: '原料', // 默认选中"原料"
profitOptions: ['原料', '其他选项1', '其他选项2'], // 可根据实际需求修改选项
};
},
computed: {},

View File

@@ -11,10 +11,34 @@ export default {
return {};
},
props: {
yName: {
type: String,
default: () => '元/㎡'
seriesData: {
type: Array,
default: () => []
},
xData: {
type: Array,
default: () => []
},
name: {
type: String,
default: () => { }
},
},
watch: {
// 监听 xData 变化,触发图表更新
xData: {
handler() {
this.$nextTick(() => this.initData());
},
deep: true // 深度监听数组内元素变化
},
// 监听 seriesData 变化,触发图表更新
seriesData: {
handler() {
this.$nextTick(() => this.initData());
},
deep: true // 深度监听数组内元素变化
}
},
mounted() {
this.$nextTick(() => {
@@ -69,7 +93,7 @@ export default {
interval: 0,
padding: [5, 0, 0, 0] // 标签向下偏移,避免与柱子底部重叠
},
data: ['6月', '7月', '8月', '9月', '10月', '11月']
data: this.xData
}
],
yAxis: [
@@ -98,7 +122,7 @@ export default {
],
series: [
{
name: '利润',
name: this.name,
type: 'line',
// yAxisIndex: 1,
lineStyle: {
@@ -118,7 +142,7 @@ export default {
{ offset: 1, color: 'rgba(40, 138, 255, 0)' }
])
},
data: [200, 280, 180, 300, 220, 350],
data: this.seriesData,
symbol: 'circle',
symbolSize: 6
},

View File

@@ -1,17 +1,17 @@
<template>
<div style="width: 100%;">
<Container :name="name" icon="cockpitItemIcon" size="operatingLarge" topSize="large">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
<div class="bottom" style="height: 420px; display: flex; width: 100%;background-color: rgba(249, 252, 255, 1);">
<!-- <top-item /> -->
<costBar :yName="yName" :dateData="dateData" />
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
<div class="bottom"
style="height: 420px; display: flex; width: 100%; background-color: rgba(249, 252, 255, 1);">
<!-- 传递处理后的分类数据给子组件 -->
<costBar :yName="yName" :categoryData="categoryData" />
</div>
</div>
</Container>
</div>
</template>
<script>
import Container from './container.vue'
import costBar from './costBar.vue'
@@ -19,89 +19,151 @@ import costBar from './costBar.vue'
export default {
name: 'ProductionStatus',
components: { Container, costBar },
// mixins: [resize],
props: {
trendData: { // 接收父组件传递的设备数据数组
trendData: { // 假设trendData是需要分类的原始数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
default: () => []
},
dateData: { // 接收父组件传递的设备数据数组
dateData: {
type: Object,
default: () => {} // 默认空数组,避免报错
default: () => { }
},
yName: { // 接收父组件传递的设备数据数组
yName: {
type: String,
default: () => '' // 默认空数组,避免报错
default: ''
},
name: { // 接收父组件传递的设备数据数组
name: {
type: String,
default: () => '趋势图' // 默认空数组,避免报错
default: '趋势图'
},
},
data() {
return {
chart: null
chart: null,
categoryData: [] // 存储分类结果每个项包含name、timeArray时间数组、rawData原始数据
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
trendData: { // 监听原始数据变化,重新分类处理
handler() {
this.processAndFormatData();
},
deep: true // 若对象内属性变化需触发,需加 deep: true
deep: true,
immediate: true // 初始加载时立即处理
},
dateData: { // 监听模式变化,重新格式化时间
handler() {
console.log('dateData', this.dateData);
this.processAndFormatData();
},
deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
methods: {
/**
* 核心处理按name分类 → 时间排序 → 提取name和时间数组
*/
processAndFormatData() {
if (!this.trendData.length) {
this.categoryData = [];
return;
}
// 1. 按name分组
const grouped = {};
this.trendData.forEach(item => {
const name = item.name;
if (!grouped[name]) {
grouped[name] = [];
}
grouped[name].push(item);
});
// 2. 对每个分组按时间从早到晚排序,并提取时间数组
const result = [];
Object.keys(grouped).forEach(name => {
// 按时间戳升序排序(时间从早到晚)
const sortedData = grouped[name].sort((a, b) => a.time - b.time);
// 3. 提取时间数组并根据mode格式化
const timeArray = sortedData.map(item => {
return this.formatTimeByMode(item.time, this.dateData.mode);
});
// 4. 组装分类结果
result.push({
name: name, // 分类名称
timeArray: timeArray, // 格式化后的时间数组(从早到晚)
rawData: sortedData // 排序后的原始数据(保留所有字段)
});
});
this.categoryData = result;
},
/**
* 根据mode格式化单个时间戳
* @param {Number} timeStamp 时间戳
* @param {Number} mode 1-日(时分秒) 2-月(月-日) 3-年(年)
* @returns 格式化后的时间字符串
*/
formatTimeByMode(timeStamp, mode) {
if (!timeStamp) return '';
const date = new Date(timeStamp);
switch (mode) {
case 1: // 日模式:时分秒 (HH:MM:SS)
return `${this.padZero(date.getHours())}:${this.padZero(date.getMinutes())}:${this.padZero(date.getSeconds())}`;
case 2: // 月模式:月-日 (MM-DD)
return `${this.padZero(date.getMonth() + 1)}-${this.padZero(date.getDate())}`; // 月份+1是因为getMonth()返回0-11
case 3: // 年模式:年 (YYYY)
return `${date.getFullYear()}`;
default:
return timeStamp.toString();
}
},
/**
* 数字补零(确保两位数)
*/
padZero(num) {
return num < 10 ? `0${num}` : num;
},
updateChart() {
// 图表更新逻辑可基于categoryData处理
}
}
}
</script>
<style lang='scss' scoped>
/* 3. 核心:滚动容器样式(固定高度+溢出滚动+隐藏滚动条) */
/* 原有样式保持不变 */
.scroll-container {
/* 1. 固定容器高度根据页面布局调整示例300px超出则滚动 */
max-height: 210px;
/* 2. 溢出滚动:内容超出高度时显示滚动功能 */
overflow-y: auto;
/* 3. 隐藏横向滚动条(防止设备名过长导致横向滚动) */
overflow-x: hidden;
/* 4. 内边距:与标题栏和容器边缘对齐 */
padding: 10px 0;
/* 5. 隐藏滚动条(兼容主流浏览器) */
/* Chrome/Safari */
&::-webkit-scrollbar {
display: none;
}
/* Firefox */
scrollbar-width: none;
/* IE/Edge */
-ms-overflow-style: none;
}
/* 设备项样式优化:增加间距,避免拥挤 */
.proBarInfo {
display: flex;
flex-direction: column;
padding: 8px 27px;
/* 调整内边距,优化排版 */
margin-bottom: 10px;
/* 设备项之间的垂直间距 */
}
/* 原有样式保留,优化细节 */
.proBarInfoEqInfo {
display: flex;
justify-content: space-between;
align-items: center;
/* 垂直居中,避免序号/文字错位 */
}
.slot {
@@ -114,14 +176,12 @@ export default {
font-size: 16px;
color: #68B5FF;
line-height: 23px;
/* 垂直居中文字 */
text-align: center;
font-style: normal;
}
.eq-name {
margin-left: 8px;
/* 增加与序号的间距 */
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
@@ -147,7 +207,6 @@ export default {
height: 14px;
border: 1px solid #ADADAD;
margin: 0 8px;
/* 优化分割线间距 */
}
.yield {
@@ -164,22 +223,18 @@ export default {
.proBarInfoEqInfoLeft {
display: flex;
align-items: center;
/* 序号和设备名垂直居中 */
}
.proBarInfoEqInfoRight {
display: flex;
align-items: center;
/* 状态/分割线/百分比垂直居中 */
}
.proBarWrapper {
position: relative;
height: 10px;
margin-top: 6px;
/* 进度条与上方信息的间距 */
border-radius: 5px;
/* 进度条圆角,优化视觉 */
overflow: hidden;
}
@@ -198,10 +253,8 @@ export default {
background: linear-gradient(65deg, rgba(53, 223, 247, 0) 0%, rgba(54, 220, 246, 0.92) 92%, #36F6E5 100%, #37ACF5 100%);
border-radius: 5px;
transition: width 0.3s ease;
/* 进度变化时添加过渡动画,更流畅 */
}
/* 图表相关样式保留 */
.chartImgBottom {
position: absolute;
bottom: 45px;
@@ -220,7 +273,6 @@ export default {
</style>
<style>
/* 全局 tooltip 样式(不使用 scoped确保生效 */
.production-status-chart-tooltip {
background: #0a2b4f77 !important;
border: none !important;

View File

@@ -5,7 +5,7 @@
<div class="kpi-content" style="padding: 14px 16px; display: flex;width: 100%;">
<div class="bottom" style="height: 420px; display: flex; width: 100%;background-color: rgba(249, 252, 255, 1);">
<!-- <top-item /> -->
<costBar :yName="yName" :dateData="dateData" />
<costBar :yName="yName" :seriesData="seriesData" :xData="xData" :name="name" :dateData="dateData" />
</div>
</div>
@@ -40,23 +40,60 @@ export default {
},
data() {
return {
chart: null
formattedList: [], // 格式化后的完整数据含处理后的time
seriesData: [], // value数组
xData: [] // 新增:存储格式化后的时间数组
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
'dateData.mode': {
handler() {
this.formatList()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
immediate: true
},
trendData: {
handler() {
this.formatList()
},
deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
methods: {
updateChart() {
formatList() {
const { mode } = this.dateData
const flatList = this.trendData.flat().filter(item => item.time) // 扁平化+过滤无效数据
// 处理数据同时提取formattedTime、value
this.formattedList = flatList.map(item => ({
...item,
formattedTime: this.formatTime(item.time, mode)
}))
// 提取value数组原逻辑不变
this.seriesData = this.formattedList.map(item => item.value)
this.name = this.formattedList.length > 0 ? this.formattedList[0].name : ''
// 新增提取格式化后的时间到timeArray与valueArray顺序一一对应
this.xData = this.formattedList.map(item => item.formattedTime)
},
formatTime(timestamp, mode) {
const date = new Date(timestamp)
const padZero = (num) => num.toString().padStart(2, '0')
switch (mode) {
case 1:
// mode=1时分秒HH:MM:SS
return `${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
case 2:
// mode=2月日MM-DD
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
case 3:
// mode=3YYYY
return date.getFullYear().toString()
default:
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
}
}
}
}

View File

@@ -206,7 +206,7 @@ export default {
.progress-yield-group {
display: flex;
flex-direction: column;
gap: 0;
gap: 4px;
}
.progress-group {

View File

@@ -256,7 +256,7 @@ export default {
.middle-line {
width: 100%;
height: 1px;
background: linear-gradient(to right, rgba(40, 203, 151, 0.3), rgba(40, 203, 151, 0.8), rgba(40, 203, 151, 0.3));
background: linear-gradient(to right, #cbcbcb rgba(255, 255, 255, 0));
}
.number {

View File

@@ -9,7 +9,7 @@
</div>
<!-- 按钮单独放在右侧容器 -->
<div class="button-wrapper">
<el-button @click="handleRoute" type="text">利润影响额</el-button>
<el-button style="border-color: #0b58ff;" @click="handleRoute">利润影响额</el-button>
</div>
</div>
<div class="container-body">

View File

@@ -5,7 +5,7 @@
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
<div style="display: flex; width: 100%; background-color: rgba(249, 252, 255, 1);">
<costBaseBarChart />
<costBaseBarChart :formattedList="formattedList" :seriesData="seriesData" :xData="xData" :name="'单耗趋势'" />
</div>
</div>
</Container>
@@ -21,7 +21,7 @@ export default {
components: { Container, costBaseBarChart },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
unitConsumptionList: { // 接收父组件传递的设备数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
},
@@ -29,154 +29,67 @@ export default {
type: String,
default: () => '' // 默认空数组,避免报错
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
dateData: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null,
parentItemList: [
{ unit: "利润总额", targetValue: 16, currentValue: 14.5, progress: 90 },
{ unit: "毛利率", targetValue: 16, currentValue: 15.2, progress: 85 },
{ unit: "单价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "净价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "销量", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "双镀面板", targetValue: 15, currentValue: 13.8, progress: 92 },
{ unit: "溢价产品销量", targetValue: 15, currentValue: 13.8, progress: 92 }
]
formattedList: [], // 格式化后的完整数据含处理后的time
seriesData: [], // value数组
xData: [] // 新增:存储格式化后的时间数组
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
'dateData.mode': {
handler() {
this.formatList()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
immediate: true
},
unitConsumptionList: {
handler() {
this.formatList()
},
deep: true
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
formatList() {
const { mode } = this.dateData
const flatList = this.unitConsumptionList.flat().filter(item => item.time) // 扁平化+过滤无效数据
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
// 处理数据同时提取formattedTime、value
this.formattedList = flatList.map(item => ({
...item,
formattedTime: this.formatTime(item.time, mode)
}))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
// 提取value数组原逻辑不变
this.seriesData = this.formattedList.map(item => item.value)
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
// 新增提取格式化后的时间到timeArray与valueArray顺序一一对应
this.xData = this.formattedList.map(item => item.formattedTime)
},
formatTime(timestamp, mode) {
const date = new Date(timestamp)
const padZero = (num) => num.toString().padStart(2, '0')
switch (mode) {
case 1:
// mode=1时分秒HH:MM:SS
return `${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
case 2:
// mode=2月日MM-DD
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
case 3:
// mode=3YYYY
return date.getFullYear().toString()
default:
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
}
this.chart.setOption(option)
}
}
}

View File

@@ -5,7 +5,7 @@
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
<div style="display: flex; width: 100%; background-color: rgba(249, 252, 255, 1);">
<costBaseBarChart />
<costBaseBarChart :formattedList="formattedList" :seriesData="seriesData" :xData="xData" :name="'产量'" />
</div>
</div>
</Container>
@@ -21,7 +21,7 @@ export default {
components: { Container, costBaseBarChart },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
outputList: { // 接收父组件传递的设备数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
},
@@ -29,154 +29,67 @@ export default {
type: String,
default: () => '' // 默认空数组,避免报错
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
dateData: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null,
parentItemList: [
{ unit: "利润总额", targetValue: 16, currentValue: 14.5, progress: 90 },
{ unit: "毛利率", targetValue: 16, currentValue: 15.2, progress: 85 },
{ unit: "单价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "净价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "销量", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "双镀面板", targetValue: 15, currentValue: 13.8, progress: 92 },
{ unit: "溢价产品销量", targetValue: 15, currentValue: 13.8, progress: 92 }
]
formattedList: [], // 格式化后的完整数据含处理后的time
seriesData: [], // value数组
xData: [] // 新增:存储格式化后的时间数组
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
'dateData.mode': {
handler() {
this.formatList()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
immediate: true
},
outputList: {
handler() {
this.formatList()
},
deep: true
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
formatList() {
const { mode } = this.dateData
const flatList = this.outputList.flat().filter(item => item.time) // 扁平化+过滤无效数据
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
// 处理数据同时提取formattedTime、value
this.formattedList = flatList.map(item => ({
...item,
formattedTime: this.formatTime(item.time, mode)
}))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
// 提取value数组原逻辑不变
this.seriesData = this.formattedList.map(item => item.value)
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
// 新增提取格式化后的时间到timeArray与valueArray顺序一一对应
this.xData = this.formattedList.map(item => item.formattedTime)
},
formatTime(timestamp, mode) {
const date = new Date(timestamp)
const padZero = (num) => num.toString().padStart(2, '0')
switch (mode) {
case 1:
// mode=1时分秒HH:MM:SS
return `${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
case 2:
// mode=2月日MM-DD
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
case 3:
// mode=3YYYY
return date.getFullYear().toString()
default:
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
}
this.chart.setOption(option)
}
}
}

View File

@@ -8,12 +8,48 @@ import * as echarts from 'echarts';
export default {
components: {},
data() {
return {};
return {
myChart: null, // 存储图表实例,避免重复创建
resizeTimer: null // 防抖定时器,优化窗口缩放
};
},
props: {
seriesData: {
type: Array,
default: () => []
},
xData: {
type: Array,
default: () => []
},
name: {
type: String,
default: () => {}
},
},
watch: {
// 监听 xData 变化,触发图表更新
xData: {
handler() {
this.$nextTick(() => this.initData());
},
deep: true // 深度监听数组内元素变化
},
// 监听 seriesData 变化,触发图表更新
seriesData: {
handler() {
this.$nextTick(() => this.initData());
},
deep: true // 深度监听数组内元素变化
}
},
mounted() {
this.$nextTick(() => {
this.initData();
});
// 组件挂载时初始化图表
this.$nextTick(() => this.initData());
},
beforeDestroy() {
// 组件销毁时清理资源,避免内存泄漏
this.destroyChart();
},
methods: {
initData() {
@@ -22,8 +58,26 @@ export default {
console.error('图表容器未找到!');
return;
}
const myChart = echarts.init(chartDom);
const option = {
// 销毁已有实例,避免重复创建(关键优化)
if (this.myChart) {
this.myChart.dispose();
}
// 初始化图表实例
this.myChart = echarts.init(chartDom);
const option = this.getChartOption(); // 抽离配置项,便于维护
// 设置配置项渲染图表
this.myChart.setOption(option, true); // 第二个参数 true 表示全量更新
// 绑定窗口缩放事件(防抖优化)
this.bindResizeEvent();
},
// 抽离图表配置项,提高可维护性
getChartOption() {
return {
tooltip: {
trigger: 'axis',
axisPointer: {
@@ -31,27 +85,18 @@ export default {
label: {
backgroundColor: '#6a7985'
}
},
// 优化tooltip内容区分各系列含义
formatter: (params) => {
let html = `${params[0].axisValue}<br/>`;
params.forEach(item => {
// 直接使用系列名,无需映射,仅保留单位判断
html += `${item.marker} ${item.seriesName}: ${item.value}${item.seriesName === '完成率' ? '%' : '片'}<br/>`;
});
return html;
}
},
grid: {
top: 50,
bottom: 30, // 增大底部间距避免柱子与X轴标签重叠
bottom: 30,
right: 70,
left: 50,
},
xAxis: [
{
type: 'category',
boundaryGap: true, // 开启边界间隙,让柱子居中显示,不贴边
boundaryGap: true,
axisTick: { show: false },
axisLine: {
show: true,
@@ -61,24 +106,22 @@ export default {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
interval: 0,
padding: [5, 0, 0, 0] // 标签向下偏移,避免与柱子底部重叠
padding: [5, 0, 0, 0]
},
data: ['6月', '7月', '8月', '9月', '10月', '11月']
data: this.xData // 绑定监听的 xData
}
],
yAxis: [
// 左侧Y轴目标/达标/未达标(数量,单位“片”)
{
type: 'value',
// name: '元/吨',
nameTextStyle: {
color: 'rgba(0, 0, 0, 0.45)',
fontSize: 12,
align: 'right'
},
min: 0, // 最小值设0确保柱子从X轴底部开始不超过X轴
max: (value) => Math.ceil(value.max * 1.1), // 最大值留10%余量,避免柱子顶满
scale: false, // 关闭缩放强制从0开始
min: 0,
max: (value) => Math.ceil((value.max || 1) * 1.1), // 处理 max 为 0 的情况
scale: false,
axisTick: { show: false },
axisLabel: {
color: 'rgba(0, 0, 0, 0.45)',
@@ -88,65 +131,30 @@ export default {
splitLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
splitNumber: 4
},
// 右侧Y轴完成率百分比
// {
// type: 'value',
// // name: '%',
// nameTextStyle: {
// color: 'rgba(0, 0, 0, 0.45)',
// fontSize: 12,
// align: 'left'
// },
// min: 0,
// max: 100, // 完成率最大100%,符合业务逻辑
// axisTick: { show: false },
// axisLabel: {
// color: 'rgba(0, 0, 0, 0.45)',
// fontSize: 12,
// formatter: '{value}%'
// },
// splitLine: { show: false }, // 不重复显示分割线
// axisLine: { lineStyle: { color: 'rgba(0, 0, 0, 0.15)' } },
// splitNumber: 4
// }
}
],
series: [
// 1. 完成率折线图绑定右侧百分比Y轴
// {
// name: '产销率',
// type: 'line',
// yAxisIndex: 1, // 绑定右侧Y轴
// lineStyle: {
// color: 'rgba(40, 138, 255, .5)',
// width: 2 // 线条加粗,突出重点
// },
// itemStyle: {
// color: 'rgba(40, 138, 255, 1)',
// borderColor: 'rgba(40, 138, 255, 1)', // 数据点白色边框,增强辨识度
// borderWidth: 2,
// radius: 4 // 数据点圆角,更圆润
// },
// areaStyle: {
// opacity: 0.2, // 降低面积透明度,不抢柱状图视觉焦点
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// { offset: 0, color: 'rgba(40, 138, 255, .9)' },
// { offset: 1, color: 'rgba(255, 132, 0, 0)' }
// ])
// },
// data: [65, 78, 52, 85, 60, 95, 72], // 完成率数据0-100
// symbol: 'circle', // 数据点为圆形
// symbolSize: 6 // 数据点大小
// },
// 2. 目标柱状图绑定左侧数量Y轴
{
name: '销量',
name: this.name,
type: 'bar',
yAxisIndex: 0,
barWidth: 24,
// 关键修复label 直接放在 series 下,而非 itemStyle 内
label: {
show: true, // 开启显示
position: 'top', // 标签位置,可选:'top'、'middle'、'bottom'
// 也可以使用绝对像素值定位,例如 [10, '50%']
// position: [10, '50%'],
// 标签内容格式化,这里直接显示数据值
formatter: '{c}',
// 文字样式
color: 'rgba(11, 88, 255, 1)', // 文字颜色
fontSize: 14, // 文字大小
// fontWeight: 'bold', // 文字粗细
// fontFamily: 'Arial, sans-serif' // 字体
},
itemStyle: {
// 移除多余的 normal 层级,直接配置 color 渐变
color: {
type: 'linear',
x: 0,
@@ -161,76 +169,37 @@ export default {
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: [200, 280, 180, 300, 220, 350]
},
// 3. 达标柱状图绑定左侧数量Y轴
// {
// name: '产量',
// type: 'bar',
// yAxisIndex: 0,
// barWidth: 24,
// // 关键修复label 直接放在 series 下,而非 itemStyle 内
// itemStyle: {
// // 移除多余的 normal 层级,直接配置 color 渐变
// color: {
// type: 'linear',
// x: 0,
// y: 0,
// x2: 0,
// y2: 1,
// colorStops: [
// { offset: 0, color: 'rgba(174, 239, 224, 1)' },
// { offset: 1, color: 'rgba(118, 218, 190, 1)' }
// ]
// },
// borderRadius: [4, 4, 0, 0],
// borderWidth: 0
// },
// data: [130, 220, 95, 255, 132, 332] // 达标数据(小于目标)
// },
// 4. 未达标柱状图绑定左侧数量Y轴
// {
// name: '未达标',
// type: 'bar',
// yAxisIndex: 0,
// barWidth: 18,
// itemStyle: {
// color: 'rgba(249, 164, 74, 1)',
// borderRadius: [4, 4, 0, 0],
// borderWidth: 0
// },
// data: [70, 60, 85, 45, 88, 18, 78] // 未达标数据(目标-达标)
// }
],
// 图例:区分各系列,点击可控制显示隐藏
// legend: {
// top: 0,
// left: 'center',
// itemWidth: 12,
// itemHeight: 8,
// textStyle: {
// color: 'rgba(0, 0, 0, 0.45)',
// fontSize: 12
// },
// data: ['完成率', '目标', '达标', '未达标']
// }
data: this.seriesData // 绑定监听的 seriesData
}
]
};
},
option && myChart.setOption(option);
// 绑定窗口缩放事件(防抖处理,避免频繁触发)
bindResizeEvent() {
window.removeEventListener('resize', this.handleResize); // 先移除旧事件,避免重复绑定
window.addEventListener('resize', this.handleResize);
},
// 窗口缩放适配
window.addEventListener('resize', () => {
myChart.resize();
});
// 窗口缩放处理函数(防抖)
handleResize() {
clearTimeout(this.resizeTimer);
this.resizeTimer = setTimeout(() => {
if (this.myChart) {
this.myChart.resize();
}
}, 200);
},
// 组件销毁清理
this.$once('hook:destroyed', () => {
window.removeEventListener('resize', () => {
myChart.resize();
});
myChart.dispose();
});
// 销毁图表实例和事件监听
destroyChart() {
if (this.myChart) {
window.removeEventListener('resize', this.handleResize);
this.myChart.dispose();
this.myChart = null;
}
clearTimeout(this.resizeTimer);
}
},
}
};
</script>

View File

@@ -1,353 +1,96 @@
<template>
<div style="flex: 1">
<Container :name="name" icon="cockpitItemIcon" size="operatingBasic" topSize="middle">
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
<div style="display: flex; width: 100%; background-color: rgba(249, 252, 255, 1);">
<costBaseBarChart />
<costBaseBarChart :formattedList="formattedList" :seriesData="seriesData" :xData="xData" :name="'采购单价' " />
</div>
</div>
</Container>
</div>
</template>
<script>
import Container from '../single-container.vue'
// import * as echarts from 'echarts'
import costBaseBarChart from './costBaseBarChart.vue'
export default {
name: 'ProductionStatus',
components: { Container, costBaseBarChart },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
pupList: {
type: Array,
default: () => [] // 默认空数组,避免报错
default: () => []
},
name: { // 接收父组件传递的设备数据数组
name: {
type: String,
default: () => '' // 默认空数组,避免报错
default: ''
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
dateData: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null,
parentItemList: [
{ unit: "利润总额", targetValue: 16, currentValue: 14.5, progress: 90 },
{ unit: "毛利率", targetValue: 16, currentValue: 15.2, progress: 85 },
{ unit: "单价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "净价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "销量", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "双镀面板", targetValue: 15, currentValue: 13.8, progress: 92 },
{ unit: "溢价产品销量", targetValue: 15, currentValue: 13.8, progress: 92 }
]
formattedList: [], // 格式化后的完整数据含处理后的time
seriesData: [], // value数组
xData: [] // 新增:存储格式化后的时间数组
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
'dateData.mode': {
handler() {
this.formatList()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
immediate: true
},
pupList: {
handler() {
this.formatList()
},
deep: true
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
formatList() {
const { mode } = this.dateData
const flatList = this.pupList.flat().filter(item => item.time) // 扁平化+过滤无效数据
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
// 处理数据同时提取formattedTime、value
this.formattedList = flatList.map(item => ({
...item,
formattedTime: this.formatTime(item.time, mode)
}))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
// 提取value数组原逻辑不变
this.seriesData = this.formattedList.map(item => item.value)
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
// 新增提取格式化后的时间到timeArray与valueArray顺序一一对应
this.xData = this.formattedList.map(item => item.formattedTime)
},
formatTime(timestamp, mode) {
const date = new Date(timestamp)
const padZero = (num) => num.toString().padStart(2, '0')
switch (mode) {
case 1:
// mode=1时分秒HH:MM:SS
return `${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
case 2:
// mode=2月日MM-DD
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
case 3:
// mode=3YYYY
return date.getFullYear().toString()
default:
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
}
this.chart.setOption(option)
}
}
}
</script>
<style lang='scss' scoped>
/* 3. 核心:滚动容器样式(固定高度+溢出滚动+隐藏滚动条) */
.scroll-container {
/* 1. 固定容器高度根据页面布局调整示例300px超出则滚动 */
max-height: 210px;
/* 2. 溢出滚动:内容超出高度时显示滚动功能 */
overflow-y: auto;
/* 3. 隐藏横向滚动条(防止设备名过长导致横向滚动) */
overflow-x: hidden;
/* 4. 内边距:与标题栏和容器边缘对齐 */
padding: 10px 0;
/* 5. 隐藏滚动条(兼容主流浏览器) */
/* Chrome/Safari */
&::-webkit-scrollbar {
display: none;
}
/* Firefox */
scrollbar-width: none;
/* IE/Edge */
-ms-overflow-style: none;
}
/* 设备项样式优化:增加间距,避免拥挤 */
.proBarInfo {
display: flex;
flex-direction: column;
padding: 8px 27px;
/* 调整内边距,优化排版 */
margin-bottom: 10px;
/* 设备项之间的垂直间距 */
}
/* 原有样式保留,优化细节 */
.proBarInfoEqInfo {
display: flex;
justify-content: space-between;
align-items: center;
/* 垂直居中,避免序号/文字错位 */
}
.slot {
width: 21px;
height: 23px;
background: rgba(0, 106, 205, 0.22);
backdrop-filter: blur(1.5px);
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #68B5FF;
line-height: 23px;
/* 垂直居中文字 */
text-align: center;
font-style: normal;
}
.eq-name {
margin-left: 8px;
/* 增加与序号的间距 */
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
line-height: 18px;
letter-spacing: 1px;
text-align: left;
font-style: normal;
}
.eqStatus {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
line-height: 18px;
text-align: right;
font-style: normal;
}
.splitLine {
width: 1px;
height: 14px;
border: 1px solid #ADADAD;
margin: 0 8px;
/* 优化分割线间距 */
}
.yield {
height: 18px;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 16px;
color: #00FFFF;
line-height: 18px;
text-align: right;
font-style: normal;
}
.proBarInfoEqInfoLeft {
display: flex;
align-items: center;
/* 序号和设备名垂直居中 */
}
.proBarInfoEqInfoRight {
display: flex;
align-items: center;
/* 状态/分割线/百分比垂直居中 */
}
.proBarWrapper {
position: relative;
height: 10px;
margin-top: 6px;
/* 进度条与上方信息的间距 */
border-radius: 5px;
/* 进度条圆角,优化视觉 */
overflow: hidden;
}
.proBarLine {
width: 100%;
height: 100%;
background: linear-gradient(65deg, rgba(82, 82, 82, 0) 0%, #ACACAC 100%);
opacity: 0.2;
}
.proBarLineTop {
position: absolute;
top: 0;
left: 0;
height: 100%;
background: linear-gradient(65deg, rgba(53, 223, 247, 0) 0%, rgba(54, 220, 246, 0.92) 92%, #36F6E5 100%, #37ACF5 100%);
border-radius: 5px;
transition: width 0.3s ease;
/* 进度变化时添加过渡动画,更流畅 */
}
/* 图表相关样式保留 */
.chartImgBottom {
position: absolute;
bottom: 45px;
left: 58px;
}
.line {
display: inline-block;
position: absolute;
left: 57px;
bottom: 42px;
width: 1px;
height: 20px;
background-color: #00E8FF;
}
</style>
<style>
/* 全局 tooltip 样式(不使用 scoped确保生效 */
.production-status-chart-tooltip {
background: #0a2b4f77 !important;
border: none !important;
backdrop-filter: blur(12px);
}
.production-status-chart-tooltip * {
color: #fff !important;
}
</style>

View File

@@ -5,7 +5,7 @@
<div class="kpi-content" style="padding: 14px 16px; display: flex;flex-direction: column; width: 100%;">
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
<div style="display: flex; width: 100%; background-color: rgba(249, 252, 255, 1);">
<costBaseBarChart />
<costBaseBarChart :formattedList="formattedList" :seriesData="seriesData" :name="'消耗量' " :xData="xData" />
</div>
</div>
</Container>
@@ -21,162 +21,79 @@ export default {
components: { Container, costBaseBarChart },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
consumptionList: {
type: Array,
default: () => [] // 默认空数组,避免报错
default: () => []
},
name: { // 接收父组件传递的设备数据数组
name: {
type: String,
default: () => '' // 默认空数组,避免报错
default: ''
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
dateData: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null,
parentItemList: [
{ unit: "利润总额", targetValue: 16, currentValue: 14.5, progress: 90 },
{ unit: "毛利率", targetValue: 16, currentValue: 15.2, progress: 85 },
{ unit: "单价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "净价", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "销量", targetValue: 20, currentValue: 16, progress: 80 },
{ unit: "双镀面板", targetValue: 15, currentValue: 13.8, progress: 92 },
{ unit: "溢价产品销量", targetValue: 15, currentValue: 13.8, progress: 92 }
]
formattedList: [], // 格式化后的完整数据含处理后的time
seriesData: [], // value数组
xData: [] // 新增:存储格式化后的时间数组
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
'dateData.mode': {
handler() {
this.formatList()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
immediate: true
},
consumptionList: {
handler() {
this.formatList()
},
deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
formatList() {
const { mode } = this.dateData
const flatList = this.consumptionList.flat().filter(item => item.time) // 扁平化+过滤无效数据
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
// 处理数据同时提取formattedTime、value
this.formattedList = flatList.map(item => ({
...item,
formattedTime: this.formatTime(item.time, mode)
}))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
// 提取value数组原逻辑不变
this.seriesData = this.formattedList.map(item => item.value)
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
// 新增提取格式化后的时间到timeArray与valueArray顺序一一对应
this.xData = this.formattedList.map(item => item.formattedTime)
},
formatTime(timestamp, mode) {
const date = new Date(timestamp)
const padZero = (num) => num.toString().padStart(2, '0')
switch (mode) {
case 1:
// mode=1时分秒HH:MM:SS
return `${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
case 2:
// mode=2月日MM-DD
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
case 3:
// mode=3YYYY
return date.getFullYear().toString()
default:
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
}
this.chart.setOption(option)
}
}
}

View File

@@ -14,58 +14,91 @@
<div class="label">
{{ typeName }}
</div>
<el-select class="custom-select" style="margin-left: 10px;" v-model="type" placeholder="">
<el-option v-for="item in TypeList" :key="item.value" :label="item.name" :value="item.value">
<el-select class="custom-select" style="margin-left: 10px;" v-model="selectedType" placeholder="">
<el-option v-for="item in typeList" :key="item.value" :label="item.name" :value="item.name">
</el-option>
</el-select>
</div>
<el-button type="primary" style="margin-left: 24px;">查询</el-button>
<!-- 绑定查询点击事件 -->
<el-button type="primary" style="margin-left: 24px;background-color: #0b58ff;letter-spacing: 6px;"
@click="handleQuery">
查询
</el-button>
</div>
</div>
</template>
<script>
export default {
name: 'ProductionStatus',
name: 'singleTopSelect',
components: {},
props: ['typeName','typeList'],
props: {
// 类型名称(如"原料"、"燃动力"
typeName: {
type: String,
// required: true,
default: () => '',
},
// 类型列表([{id, name}] 或 [{value, name}]
typeList: {
type: Array,
required: true,
default: () => [],
validator: val => val.every(item => item.name && (item.id || item.value)) // 校验列表格式
},
// 默认选中的基地ID支持父组件传入
defaultLevelId: {
type: Number,
default: 1
},
// 默认选中的类型名称(支持父组件传入)
defaultType: {
type: String,
default: ''
}
},
watch: {
// 监听父组件传入的默认值变化,同步更新
// defaultLevelId: {
// handler(val) {
// this.levelId = val;
// },
// immediate: true
// },
defaultType: {
handler(val) {
this.selectedType = val;
},
immediate: true
}
},
data() {
return {
levelId: '',
levelId: 1,
selectedType: '', // 初始化type变量
baseList: [
{
value: 2,
name: "宜兴",
},
{
value: 3,
name: "漳州",
},
{
value: 4,
name: "自贡",
},
{
value: 5,
name: "桐城",
},
{
value: 6,
name: "洛阳",
},
{
value: 7,
name: "合肥",
},
{ value: 1, name: "总览" },
{ value: 2, name: "宜兴" },
{ value: 3, name: "漳州" },
{ value: 4, name: "自贡" },
{ value: 5, name: "桐城" },
{ value: 6, name: "洛阳" },
{ value: 7, name: "合肥" },
]
}
},
methods: {
updateChart() { }
updateChart() { },
// 处理查询事件
handleQuery() {
// 触发自定义事件将type和levelId传递给父组件
this.$emit('query', {
type: this.type,
levelId: this.levelId
});
}
}
}
</script>
<style lang='scss' scoped>
.topSelect {
width: 1620px;

View File

@@ -4,10 +4,9 @@
<!-- 1. 移除 .kpi-content 的固定高度改为自适应 -->
<div class="kpi-content" style="padding: 14px 16px; display: flex; width: 100%;">
<!-- 新增topItem 专属包裹容器统一控制样式和布局 -->
<div class=""
style="display: flex;width: 100%; background-color: rgba(249, 252, 255, 1);">
<div class="" style="display: flex;width: 100%; background-color: rgba(249, 252, 255, 1);">
<!-- <topItem :itemList="parentItemList" /> -->
<totalProfitBar />
<totalProfitBar :name="name" :seriesData="seriesData" :xData="xData" />
</div>
<!-- 2. .top 保持 flex无需固定高度自动跟随子元素拉伸 -->
@@ -28,153 +27,72 @@ export default {
components: { Container,totalProfitBar },
// mixins: [resize],
props: {
leftEqInfoData: { // 接收父组件传递的设备数据数组
totalProfitIndict: { // 接收父组件传递的设备数据数组
type: Array,
default: () => [] // 默认空数组,避免报错
},
productionOverviewVo: { // 恢复生产概览数据(原代码注释了,需根据实际需求保留)
dateData: {
type: Object,
default: () => ({})
}
},
data() {
return {
chart: null,
parentItemList: [
{ unit: "销量", targetValue: 16, currentValue: 14.5, progress: 90 },
{ unit: "产量", targetValue: 16, currentValue: 15.2, progress: 85 },
]
name:'',
formattedList: [], // 格式化后的完整数据含处理后的time
seriesData: [], // value数组
xData: [] // 新增:存储格式化后的时间数组
}
},
watch: {
productionOverviewVo: {
handler(newValue, oldValue) {
this.updateChart()
'dateData.mode': {
handler() {
this.formatList()
},
deep: true // 若对象内属性变化需触发,需加 deep: true
}
},
mounted() {
// 初始化图表(若需展示图表,需在模板中添加对应 DOM
// this.$nextTick(() => this.updateChart())
},
beforeDestroy() {
// 销毁图表,避免内存泄漏
if (this.chart) {
this.chart.dispose()
this.chart = null
immediate: true
},
totalProfitIndict: {
handler() {
this.formatList()
},
deep: true
}
},
methods: {
updateChart() {
// 注意:原代码中图表依赖 id 为 "productionStatusChart" 的 DOM需在模板中补充否则会报错
// 示例:在 Container 内添加 <div id="productionStatusChart" style="height: 200px;"></div>
if (!document.getElementById('productionStatusChart')) return
formatList() {
const { mode } = this.dateData
const flatList = this.totalProfitIndict.flat().filter(item => item.time) // 扁平化+过滤无效数据
if (this.chart) this.chart.dispose()
this.chart = echarts.init(document.getElementById('productionStatusChart'))
// 处理数据同时提取formattedTime、value
this.formattedList = flatList.map(item => ({
...item,
formattedTime: this.formatTime(item.time, mode)
}))
const data = [
this.productionOverviewVo.input || 0,
this.productionOverviewVo.output || 0,
this.productionOverviewVo.ng || 0,
this.productionOverviewVo.lowValue || 0,
this.productionOverviewVo.scrap || 0,
this.productionOverviewVo.inProcess || 0,
this.productionOverviewVo.engineer || 0
]
// 提取value数组原逻辑不变
this.seriesData = this.formattedList.map(item => item.value)
this.name = this.formattedList.length > 0 ? this.formattedList[0].name : ''
// 新增提取格式化后的时间到timeArray与valueArray顺序一一对应
this.xData = this.formattedList.map(item => item.formattedTime)
},
const option = {
type: 'bar',
grid: { left: 51, right: 40, top: 50, bottom: 45 },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
className: 'production-status-chart-tooltip'
},
xAxis: {
type: 'category',
offset: 8,
data: ['投入', '产出', '待判', '低价值', '报废', '在制', '实验片'],
axisTick: { show: false },
axisLine: { show: true, onZero: false, lineStyle: { color: '#00E8FF' } },
axisLabel: {
color: 'rgba(255,255,255,0.7)',
fontSize: 12,
interval: 0,
width: 38,
overflow: 'break'
}
},
yAxis: {
type: 'value',
name: '单位/片',
nameTextStyle: { color: 'rgba(255,255,255,0.7)', fontSize: 14, align: 'left' },
min: () => 0,
max: (value) => Math.ceil(value.max),
scale: true,
axisTick: { show: false },
axisLabel: { color: 'rgba(255,255,255,0.7)', fontSize: 12 },
splitLine: { lineStyle: { color: 'RGBA(24, 88, 100, 0.6)', type: 'dashed' } },
axisLine: { show: true, lineStyle: { color: '#00E8FF' } }
},
series: [
{
type: 'pictorialBar',
label: { show: true, position: 'top', distance: -3, color: '#89CDFF', fontSize: 11 },
symbolSize: [20, 8],
symbolOffset: [0, 5],
z: 20,
itemStyle: {
borderColor: '#3588C7',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
data: data
},
{
type: 'bar',
barWidth: 20,
itemStyle: {
borderWidth: 1,
borderColor: '#3588C7',
opacity: 0.8,
color: {
x: 0, y: 0, x2: 0, y2: 1,
type: 'linear',
global: false,
colorStops: [
{ offset: 0, color: 'rgba(73,178,255,0)' },
{ offset: 0.5, color: 'rgba(0, 232, 255, .5)' },
{ offset: 1, color: 'rgba(0, 232, 255, 1)' }
]
}
},
tooltip: { show: false },
data: data
},
{
type: 'pictorialBar',
symbolSize: [20, 8],
symbolOffset: [0, -4],
z: 12,
symbolPosition: 'end',
itemStyle: {
borderColor: 'rgba(0, 232, 255, 1)',
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'RGBA(22, 89, 98, 1)' },
{ offset: 1, color: '#3588C7' }
])
},
tooltip: { show: false },
data: data
}
]
formatTime(timestamp, mode) {
const date = new Date(timestamp)
const padZero = (num) => num.toString().padStart(2, '0')
switch (mode) {
case 1:
// mode=1时分秒HH:MM:SS
return `${padZero(date.getHours())}:${padZero(date.getMinutes())}:${padZero(date.getSeconds())}`
case 2:
// mode=2月日MM-DD
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
case 3:
// mode=3YYYY
return date.getFullYear().toString()
default:
return `${padZero(date.getMonth() + 1)}-${padZero(date.getDate())}`
}
this.chart.setOption(option)
}
}
}

View File

@@ -10,6 +10,36 @@ export default {
data() {
return {};
},
props: {
seriesData: {
type: Array,
default: () => []
},
xData: {
type: Array,
default: () => []
},
name: {
type: String,
default: () => { }
},
},
watch: {
// 监听 xData 变化,触发图表更新
xData: {
handler() {
this.$nextTick(() => this.initData());
},
deep: true // 深度监听数组内元素变化
},
// 监听 seriesData 变化,触发图表更新
seriesData: {
handler() {
this.$nextTick(() => this.initData());
},
deep: true // 深度监听数组内元素变化
}
},
mounted() {
this.$nextTick(() => {
this.initData();
@@ -37,7 +67,7 @@ export default {
let html = `${params[0].axisValue}<br/>`;
params.forEach(item => {
// 直接使用系列名,无需映射,仅保留单位判断
html += `${item.marker} ${item.seriesName}: ${item.value}${item.seriesName === '完成率' ? '%' : '片'}<br/>`;
html += `${item.marker} ${item.seriesName}: ${item.value}${'元'}<br/>`;
});
return html;
}
@@ -63,7 +93,7 @@ export default {
interval: 0,
padding: [5, 0, 0, 0] // 标签向下偏移,避免与柱子底部重叠
},
data: ['漳州', '桐城', '合肥', '宜兴', '自贡', '洛阳']
data: this.xData // 绑定监听的 xData
}
],
yAxis: [
@@ -140,11 +170,25 @@ export default {
// },
// 2. 目标柱状图绑定左侧数量Y轴
{
name: '销量',
name:this.name,
type: 'bar',
yAxisIndex: 0,
barWidth: 24,
// 关键修复label 直接放在 series 下,而非 itemStyle 内
label: {
show: true, // 开启显示
position: 'top', // 标签位置,可选:'top'、'middle'、'bottom'
// 也可以使用绝对像素值定位,例如 [10, '50%']
// position: [10, '50%'],
// 标签内容格式化,这里直接显示数据值
formatter: '{c}',
// 文字样式
color: 'rgba(11, 88, 255, 1)', // 文字颜色
fontSize: 14, // 文字大小
// fontWeight: 'bold', // 文字粗细
// fontFamily: 'Arial, sans-serif' // 字体
},
itemStyle: {
// 移除多余的 normal 层级,直接配置 color 渐变
color: {
@@ -161,7 +205,7 @@ export default {
borderRadius: [4, 4, 0, 0],
borderWidth: 0
},
data: [200, 280, 180, 300, 220, 350]
data: this.seriesData
},
// 3. 达标柱状图绑定左侧数量Y轴
// {

View File

@@ -35,7 +35,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<profitLineChart :yName="'元/㎡'" :trendData="trendData" />
<profitLineChart :yName="'元/㎡'" :trendData="trendData" :dateData="dateData" />
</div>
</div>
</div>
@@ -83,9 +83,7 @@ export default {
timer: null,
beilv: 1,
value: 100,
startTime:undefined,
endTime: undefined,
mode: undefined,
dateData:{},
levelId:undefined,
itemData: [],
trendData: [],
@@ -167,7 +165,6 @@ export default {
},
methods: {
getData() {
// 基于选中的数据构建请求参数(根据实际接口需求调整)
const requestParams = {
// startTime: this.startTime,
// endTime: this.endTime,
@@ -192,16 +189,18 @@ export default {
handleTimeChange(obj) {
console.log(obj, 'obj');
this.startTime = obj.startTime
this.endTime = obj.endTime
this.mode = obj.mode
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
selectChange(data) {
console.log('选中的数据:', data);
this.levelId = data
if (this.startTime && this.endTime) {
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},

View File

@@ -35,7 +35,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<profitLineChart :yName="'元/㎡'" :trendData="trendData" />
<profitLineChart :yName="'元/㎡'" :trendData="trendData" :dateData="dateData" />
</div>
</div>
</div>
@@ -83,9 +83,7 @@ export default {
timer: null,
beilv: 1,
value: 100,
startTime: undefined,
endTime: undefined,
mode: undefined,
dateData:{},
levelId: undefined,
itemData: [],
trendData: [],
@@ -192,16 +190,18 @@ export default {
handleTimeChange(obj) {
console.log(obj, 'obj');
this.startTime = obj.startTime
this.endTime = obj.endTime
this.mode = obj.mode
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
selectChange(data) {
console.log('选中的数据:', data);
this.levelId = data
if (this.startTime && this.endTime) {
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},

View File

@@ -3,7 +3,7 @@
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<ReportHeader top-title="营业收入" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
/>
@timeRangeChange="handleTimeChange" />
<div class="main-body" style="
flex: 1;
display: flex;
@@ -16,8 +16,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<operatingSalesRevenue />
<premProdStatus />
<operatingSalesRevenue :saleData="saleData" />
<premProdStatus :premiumProduct="premiumProduct" :salesProportion="salesProportion" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: 6px;">
@@ -26,7 +26,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<operatingLineChart />
<operatingLineChart :salesTrendMap="salesTrendMap" :grossMarginTrendMap="grossMarginTrendMap" />
<!-- <keyWork /> -->
</div>
</div>
@@ -49,12 +49,8 @@ import operatingSalesRevenue from "./components/operatingSalesRevenue.vue";
import premProdStatus from "./components/premProdStatus.vue";
import { mapState } from "vuex";
import operatingLineChart from "./components/operatingLineChart";
// import coreBottomLeft from "./components/coreBottomLeft.vue";
// import orderProgress from "./components/orderProgress.vue";
// import keyWork from "./components/keyWork.vue";
import { getSalesRevenueData } from '@/api/cockpit'
import moment from "moment";
// import html2canvas from 'html2canvas'
// import JsPDF from 'jspdf'
export default {
name: "DayReport",
components: {
@@ -71,6 +67,11 @@ export default {
timer: null,
beilv: 1,
value: 100,
saleData: {},
premiumProduct: {},
salesTrendMap: {},
grossMarginTrendMap: {},
salesProportion:{},
};
},
@@ -128,14 +129,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
this.loopTime();
console.log(1111);
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {
@@ -146,6 +139,24 @@ export default {
};
},
methods: {
getData(obj) {
getSalesRevenueData({
startTime: obj.startTime,
endTime: obj.endTime,
timeDim: 1
}).then((res) => {
console.log(res);
this.saleData = res.data.SaleData
this.premiumProduct = res.data.premiumProduct
this.salesTrendMap = res.data.salesTrendMap
this.grossMarginTrendMap = res.data.grossMarginTrendMap
this.salesProportion = res.data.salesProportion ? res.data.salesProportion : {}
})
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.getData(obj)
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
@@ -153,28 +164,6 @@ export default {
this.clientWidth = value;
this.beilv2 = this.clientWidth / 1920;
},
getToday8StartTimestamp() {
const date = new Date(); // 获取当前时间
// 将时设为8、分0、秒0、毫秒0
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
// 获取第二天早上八点的时间戳
getTomorrow8EndTimestamp() {
const date = new Date(); // 获取当前时间
// 先加一天,再设置为早上八点
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
loopTime() {
const _this = this;
_this.timer = setInterval(function () {
// _this.getData()
}, 60000);
},
change() {
this.isFullScreen = screenfull.isFullscreen;
},
@@ -211,16 +200,6 @@ export default {
}
screenfull.toggle(this.$refs.dayReportB);
},
changeDate(val) {
this.date = val;
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
if (this.date === moment().format("yyyy-MM-DD")) {
this.loopTime();
} else {
clearInterval(this.timer);
}
},
// 导出
// exportPDF() {
// this.$message.success('正在导出,请稍等!')

View File

@@ -35,7 +35,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<profitLineChart :yName="'元/㎡'" :trendData="trendData" />
<profitLineChart :yName="'元/㎡'" :trendData="trendData" :dateData="dateData" />
</div>
</div>
</div>
@@ -83,9 +83,7 @@ export default {
timer: null,
beilv: 1,
value: 100,
startTime: undefined,
endTime: undefined,
mode: undefined,
dateData:{},
levelId: undefined,
itemData: [],
trendData: [],
@@ -192,16 +190,17 @@ export default {
handleTimeChange(obj) {
console.log(obj, 'obj');
this.startTime = obj.startTime
this.endTime = obj.endTime
this.mode = obj.mode
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
selectChange(data) {
console.log('选中的数据:', data);
this.levelId = data
if (this.startTime && this.endTime) {
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},

View File

@@ -35,7 +35,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<profitLineChart :yName="'元/㎡'" :trendData="trendData" />
<profitLineChart :yName="'元/㎡'" :trendData="trendData" :dateData="dateData" />
</div>
</div>
</div>
@@ -83,9 +83,7 @@ export default {
timer: null,
beilv: 1,
value: 100,
startTime: undefined,
endTime: undefined,
mode: undefined,
dateData:{},
levelId: undefined,
itemData: [],
trendData: [],
@@ -192,16 +190,17 @@ export default {
handleTimeChange(obj) {
console.log(obj, 'obj');
this.startTime = obj.startTime
this.endTime = obj.endTime
this.mode = obj.mode
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
selectChange(data) {
console.log('选中的数据:', data);
this.levelId = data
if (this.startTime && this.endTime) {
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},

View File

@@ -2,7 +2,8 @@
<div id="dayReport" class="dayReport" :style="styles">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<ReportHeader size="psi" top-title="利润影响额分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange" />
<ReportHeader size="psi" top-title="利润影响额分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
@timeRangeChange="handleTimeChange" />
<div class="main-body" style="
margin-top: -20px;
flex: 1;
@@ -16,7 +17,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<singleTopSelect typeName="分析对象" />
<singleTopSelect @query="handleGetData" :defaultType="'原料'" :typeList="typeList" typeName="分析对象" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: 6px;">
@@ -25,7 +26,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<totalProfit />
<totalProfit :totalProfitIndict="totalProfitIndict" :dateData="dateData" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: 6px;">
@@ -34,7 +35,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<profitLineChart :name=" '总利润趋势·元' " :yName="'元' " />
<profitLineChart :trendData="totalProfitTrend" :dateData="dateData" :name=" '总利润趋势·元' " :yName="'元' " />
</div>
</div>
</div>
@@ -52,20 +53,13 @@
import ReportHeader from "./costComponents/single/noRouterHeader.vue";
import { Sidebar } from "../../layout/components";
import screenfull from "screenfull";
import changeBase from "./costComponents/changeBase";
// import changeBase from "./costComponents/changeBase";
import totalProfit from "./costComponents/totalProfit.vue";
import profitLineChart from "./costComponents/profitTotalChart.vue";
import { mapState } from "vuex";
import singleTopSelect from "./costComponents/singleTopSelect.vue";
// import PSDO from "./components/PSDO.vue";
// import psiLineChart from "./components/psiLineChart.vue";
// import coreBottomLeft from "./components/coreBottomLeft.vue";
// import orderProgress from "./components/orderProgress.vue";
// import keyWork from "./components/keyWork.vue";
import moment from "moment";
// import html2canvas from 'html2canvas'
// import JsPDF from 'jspdf'
import { getProfitImpactList } from '@/api/cockpit'
export default {
name: "DayReport",
components: {
@@ -78,37 +72,19 @@ export default {
},
data() {
return {
weekArr: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
isFullScreen: false,
timer: null,
beilv: 1,
value: 100,
coreProductVisualAlarmVO: [],
defect: {},
centerEqInfo: [
{ title: "工单数量", num: 0 },
{ title: "总产量/吨", num: 0 },
{ title: "生产合格率", num: "0%" },
{ title: "设备运行数量", num: 0 },
{ title: "累计能耗/kwh", num: 0 },
],
outputTrend: {},
coreProductVisualProcessVO: [],
coreProductVisualWorkOrderVO: {},
date: "",
weekDay: "", // 导出报表用
productNum: "",
coreProductVisualLineVO: [],
lineYieldVo: {}, // 产线良率
productionOverviewVo: [], // 生产状况
qualityDistributionVo: {}, // 本日不良分布
equipmentUtilizationVo: {}, // 设备性能稼动率
chipPowerDistributionVo: {}, // 芯片功率分布
modulePowerDistributionVo: {}, // 组件功率分布
chipPowerTrendVo: {},
modulePowerTrendVo: {},
equipmentProVo: [], // 表格
equipmentStateVo: [], // 设备状态分布
dateData: {},
levelId: 1,
analysisObject: [],
typeList: [{
name: '原料',
id: 1,
}],
totalProfitIndict: [],
totalProfitTrend:[],
};
},
@@ -166,14 +142,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
this.loopTime();
console.log(1111);
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {
@@ -184,6 +152,49 @@ export default {
};
},
methods: {
getData() {
// 基于选中的数据构建请求参数(根据实际接口需求调整)
// let analysisObject = []
const requestParams = {
// startTime: this.startTime,
// endTime: this.endTime,
// mode: this.mode,
startTime: 1762704000290,
endTime: 1762790399290,
mode: 1,
// analysisObject: this.analysisObject,
analysisObject: ["石灰石"],
levelId: this.levelId ? this.levelId : 1
};
// 调用接口
getProfitImpactList(requestParams).then((res) => {
this.totalProfitIndict = res.data.TotalProfitIndict
this.totalProfitTrend = res.data.TotalProfitTrend
});
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
handleGetData(data) {
console.log('从子组件接收的参数:', data);
// params中包含type和levelId
const { type, levelId } = data;
this.analysisObject = []
this.analysisObject.push(type)
this.levelId = levelId
// 在这里进行后续处理,如发起请求等
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
@@ -191,28 +202,6 @@ export default {
this.clientWidth = value;
this.beilv2 = this.clientWidth / 1920;
},
getToday8StartTimestamp() {
const date = new Date(); // 获取当前时间
// 将时设为8、分0、秒0、毫秒0
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
// 获取第二天早上八点的时间戳
getTomorrow8EndTimestamp() {
const date = new Date(); // 获取当前时间
// 先加一天,再设置为早上八点
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
loopTime() {
const _this = this;
_this.timer = setInterval(function () {
// _this.getData()
}, 60000);
},
change() {
this.isFullScreen = screenfull.isFullscreen;
},
@@ -249,16 +238,6 @@ export default {
}
screenfull.toggle(this.$refs.dayReportB);
},
changeDate(val) {
this.date = val;
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
if (this.date === moment().format("yyyy-MM-DD")) {
this.loopTime();
} else {
clearInterval(this.timer);
}
},
// 导出
// exportPDF() {
// this.$message.success('正在导出,请稍等!')

View File

@@ -17,7 +17,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<changeBase />
<changeBase @selectChange="selectChange" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: -20px;">
@@ -35,7 +35,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<profitLineChart :yName="'元/㎡'" :dateData="dateData" />
<profitLineChart :yName="'元/㎡'" :dateData="dateData" :trendData="trendData" />
</div>
</div>
</div>
@@ -152,8 +152,9 @@ export default {
};
},
methods: {
getData(obj) {
this.dateData = obj
getData() {
// this.dateData = obj
// console.log('obj', obj);
getCostAnalysisXXCostList({
startTime: "1762704000290",
endTime: "1762790399290",
@@ -172,7 +173,20 @@ export default {
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.getData(obj)
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
selectChange(data) {
console.log('选中的数据:', data);
this.levelId = data
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });

View File

@@ -2,7 +2,8 @@
<div id="dayReport" class="dayReport" :style="styles">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<ReportHeader size="psi" top-title="单项燃料分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange" />
<ReportHeader size="psi" top-title="单项燃料分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
@timeRangeChange="handleTimeChange" />
<div class="main-body" style="
margin-top: -20px;
flex: 1;
@@ -16,7 +17,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<singleTopSelect typeName="燃料" />
<singleTopSelect :defaultType="'燃料成本'" :typeList="typeList" @query="handleGetData" typeName="燃料" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: 8px;">
@@ -25,8 +26,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<topLeftChart :name=" '采购单价·元/m³' " />
<topRightChart :name="'消耗量·m³'" />
<topLeftChart :dateData="dateData" :pupList="pupList" :name=" '采购单价·元/m³' " />
<topRightChart :dateData="dateData" :consumptionList="consumptionList" :name="'消耗量·m³'" />
</div>
</div>
@@ -36,8 +37,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<bottomLeftChart :name="'单耗趋势·m³/㎡'" />
<bottomLeftChart :name="'产量·㎡'" />
<bottomLeftChart :dateData="dateData" :unitConsumptionList="unitConsumptionList" :name="'单耗趋势·m³/㎡'" />
<bottomRightChart :dateData="dateData" :outputList="outputList" :name="'产量·㎡'" />
</div>
</div>
</div>
@@ -63,6 +64,7 @@ import topLeftChart from "./costComponents/single/topLeftChart.vue";
import topRightChart from "./costComponents/single/topRightChart.vue";
import bottomLeftChart from "./costComponents/single/bottomLeftChart.vue";
import bottomRightChart from "./costComponents/single/bottomRightChart.vue";
import { getCostAnalysisXXCostList } from '@/api/cockpit'
// import PSDO from "./components/PSDO.vue";
// import psiLineChart from "./components/psiLineChart.vue";
@@ -93,32 +95,16 @@ export default {
timer: null,
beilv: 1,
value: 100,
coreProductVisualAlarmVO: [],
defect: {},
centerEqInfo: [
{ title: "工单数量", num: 0 },
{ title: "总产量/吨", num: 0 },
{ title: "生产合格率", num: "0%" },
{ title: "设备运行数量", num: 0 },
{ title: "累计能耗/kwh", num: 0 },
],
outputTrend: {},
coreProductVisualProcessVO: [],
coreProductVisualWorkOrderVO: {},
date: "",
weekDay: "", // 导出报表用
productNum: "",
coreProductVisualLineVO: [],
lineYieldVo: {}, // 产线良率
productionOverviewVo: [], // 生产状况
qualityDistributionVo: {}, // 本日不良分布
equipmentUtilizationVo: {}, // 设备性能稼动率
chipPowerDistributionVo: {}, // 芯片功率分布
modulePowerDistributionVo: {}, // 组件功率分布
chipPowerTrendVo: {},
modulePowerTrendVo: {},
equipmentProVo: [], // 表格
equipmentStateVo: [], // 设备状态分布
pupList: [],
consumptionList: [],
unitConsumptionList: [],
outputList: [],
analysisObject: [],
dateData: {},
typeList: [{
name: '燃料成本',
id: 1,
}]
};
},
@@ -176,14 +162,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
this.loopTime();
console.log(1111);
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {
@@ -192,8 +170,57 @@ export default {
this.beilv = _this.clientWidth / 1920;
})();
};
if (this.$route.query.name) {
this.analysisObject = [this.$route.query.name]
} else {
this.analysisObject = ['燃料成本']
}
},
methods: {
getData() {
// 基于选中的数据构建请求参数(根据实际接口需求调整)
// let analysisObject = []
const requestParams = {
// startTime: this.startTime,
// endTime: this.endTime,
// mode: this.mode,
startTime: 1762704000000,
endTime: 1762790400000,
mode: 1,
analysisObject: this.analysisObject,
levelId: this.levelId ? this.levelId : 1
};
// 调用接口
getCostAnalysisXXCostList(requestParams).then((res) => {
this.pupList = res.data[0]
this.consumptionList = res.data[1]
this.unitConsumptionList = res.data[2]
this.outputList = res.data[3]
});
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
handleGetData(data) {
console.log('从子组件接收的参数:', data);
// params中包含type和levelId
const { type, levelId } = data;
this.analysisObject = []
this.analysisObject.push(type)
this.levelId = levelId
// 在这里进行后续处理,如发起请求等
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
@@ -201,28 +228,6 @@ export default {
this.clientWidth = value;
this.beilv2 = this.clientWidth / 1920;
},
getToday8StartTimestamp() {
const date = new Date(); // 获取当前时间
// 将时设为8、分0、秒0、毫秒0
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
// 获取第二天早上八点的时间戳
getTomorrow8EndTimestamp() {
const date = new Date(); // 获取当前时间
// 先加一天,再设置为早上八点
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
loopTime() {
const _this = this;
_this.timer = setInterval(function () {
// _this.getData()
}, 60000);
},
change() {
this.isFullScreen = screenfull.isFullscreen;
},
@@ -259,16 +264,6 @@ export default {
}
screenfull.toggle(this.$refs.dayReportB);
},
changeDate(val) {
this.date = val;
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
if (this.date === moment().format("yyyy-MM-DD")) {
this.loopTime();
} else {
clearInterval(this.timer);
}
},
// 导出
// exportPDF() {
// this.$message.success('正在导出,请稍等!')

View File

@@ -2,7 +2,8 @@
<div id="dayReport" class="dayReport" :style="styles">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<ReportHeader size="psi" top-title="单项包装辅材分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange" />
<ReportHeader size="psi" top-title="单项包装辅材分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
@timeRangeChange="handleTimeChange" />
<div class="main-body" style="
margin-top: -20px;
flex: 1;
@@ -16,7 +17,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<singleTopSelect typeName="包装辅材" />
<singleTopSelect :defaultType="'包装物辅材成本'" :typeList="typeList" @query="handleGetData" typeName="包装辅材" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: 8px;">
@@ -25,8 +26,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<topLeftChart :name=" '采购单价·元/只' " />
<topRightChart :name="'消耗量·只'" />
<topLeftChart :dateData="dateData" :pupList="pupList" :name=" '采购单价·元/只' " />
<topRightChart :dateData="dateData" :consumptionList="consumptionList" :name="'消耗量·只'" />
</div>
</div>
@@ -36,8 +37,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<bottomLeftChart :name="'单耗趋势·只/㎡'" />
<bottomLeftChart :name="'产量·㎡'" />
<bottomLeftChart :dateData="dateData" :unitConsumptionList="unitConsumptionList" :name="'单耗趋势·只/㎡'" />
<bottomRightChart :dateData="dateData" :outputList="outputList" :name="'产量·㎡'" />
</div>
</div>
</div>
@@ -64,6 +65,7 @@ import topLeftChart from "./costComponents/single/topLeftChart.vue";
import topRightChart from "./costComponents/single/topRightChart.vue";
import bottomLeftChart from "./costComponents/single/bottomLeftChart.vue";
import bottomRightChart from "./costComponents/single/bottomRightChart.vue";
import { getCostAnalysisXXCostList } from '@/api/cockpit'
// import PSDO from "./components/PSDO.vue";
// import psiLineChart from "./components/psiLineChart.vue";
@@ -94,32 +96,16 @@ export default {
timer: null,
beilv: 1,
value: 100,
coreProductVisualAlarmVO: [],
defect: {},
centerEqInfo: [
{ title: "工单数量", num: 0 },
{ title: "总产量/吨", num: 0 },
{ title: "生产合格率", num: "0%" },
{ title: "设备运行数量", num: 0 },
{ title: "累计能耗/kwh", num: 0 },
],
outputTrend: {},
coreProductVisualProcessVO: [],
coreProductVisualWorkOrderVO: {},
date: "",
weekDay: "", // 导出报表用
productNum: "",
coreProductVisualLineVO: [],
lineYieldVo: {}, // 产线良率
productionOverviewVo: [], // 生产状况
qualityDistributionVo: {}, // 本日不良分布
equipmentUtilizationVo: {}, // 设备性能稼动率
chipPowerDistributionVo: {}, // 芯片功率分布
modulePowerDistributionVo: {}, // 组件功率分布
chipPowerTrendVo: {},
modulePowerTrendVo: {},
equipmentProVo: [], // 表格
equipmentStateVo: [], // 设备状态分布
pupList: [],
consumptionList: [],
unitConsumptionList: [],
outputList: [],
dateData:{},
analysisObject: [],
typeList: [{
name: '包装物辅材成本',
id: 1,
}]
};
},
@@ -177,14 +163,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
this.loopTime();
console.log(1111);
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {
@@ -193,8 +171,57 @@ export default {
this.beilv = _this.clientWidth / 1920;
})();
};
if (this.$route.query.name) {
this.analysisObject = [this.$route.query.name]
} else {
this.analysisObject = ['包装物辅材成本']
}
},
methods: {
getData() {
// 基于选中的数据构建请求参数(根据实际接口需求调整)
// let analysisObject = []
const requestParams = {
// startTime: this.startTime,
// endTime: this.endTime,
// mode: this.mode,
startTime: 1762704000000,
endTime: 1762790400000,
mode: 1,
analysisObject: this.analysisObject,
levelId: this.levelId ? this.levelId : 1
};
// 调用接口
getCostAnalysisXXCostList(requestParams).then((res) => {
this.pupList = res.data[0]
this.consumptionList = res.data[1]
this.unitConsumptionList = res.data[2]
this.outputList = res.data[3]
});
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
handleGetData(data) {
console.log('从子组件接收的参数:', data);
// params中包含type和levelId
const { type, levelId } = data;
this.analysisObject = []
this.analysisObject.push(type)
this.levelId = levelId
// 在这里进行后续处理,如发起请求等
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
@@ -202,28 +229,6 @@ export default {
this.clientWidth = value;
this.beilv2 = this.clientWidth / 1920;
},
getToday8StartTimestamp() {
const date = new Date(); // 获取当前时间
// 将时设为8、分0、秒0、毫秒0
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
// 获取第二天早上八点的时间戳
getTomorrow8EndTimestamp() {
const date = new Date(); // 获取当前时间
// 先加一天,再设置为早上八点
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
loopTime() {
const _this = this;
_this.timer = setInterval(function () {
// _this.getData()
}, 60000);
},
change() {
this.isFullScreen = screenfull.isFullscreen;
},
@@ -260,16 +265,6 @@ export default {
}
screenfull.toggle(this.$refs.dayReportB);
},
changeDate(val) {
this.date = val;
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
if (this.date === moment().format("yyyy-MM-DD")) {
this.loopTime();
} else {
clearInterval(this.timer);
}
},
// 导出
// exportPDF() {
// this.$message.success('正在导出,请稍等!')

View File

@@ -2,7 +2,8 @@
<div id="dayReport" class="dayReport" :style="styles">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<ReportHeader size="psi" top-title="单项原料分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange" />
<ReportHeader size="psi" top-title="单项原料分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
@timeRangeChange="handleTimeChange" />
<div class="main-body" style="
margin-top: -20px;
flex: 1;
@@ -16,7 +17,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<singleTopSelect typeName="原料" />
<singleTopSelect typeName="原料" @query="handleGetData" :defaultType="'原料成本'" :typeList="rawTypeList" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top:8px;">
@@ -25,8 +26,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<topLeftChart :name=" '采购单价·元/吨' " />
<topRightChart :name="'消耗量·吨'" />
<topLeftChart :dateData="dateData" :pupList="pupList" :name=" '采购单价·元/吨' " />
<topRightChart :dateData="dateData" :consumptionList="consumptionList" :name="'消耗量·吨'" />
</div>
</div>
@@ -36,8 +37,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<bottomLeftChart :name="'单耗趋势·吨/㎡'" />
<bottomLeftChart :name="'产量·㎡'" />
<bottomLeftChart :dateData="dateData" :unitConsumptionList="unitConsumptionList" :name="'单耗趋势·吨/㎡'" />
<bottomRightChart :dateData="dateData" :outputList="outputList" :name="'产量·㎡'" />
</div>
</div>
</div>
@@ -63,12 +64,7 @@ import topLeftChart from "./costComponents/single/topLeftChart.vue";
import topRightChart from "./costComponents/single/topRightChart.vue";
import bottomLeftChart from "./costComponents/single/bottomLeftChart.vue";
import bottomRightChart from "./costComponents/single/bottomRightChart.vue";
// import PSDO from "./components/PSDO.vue";
// import psiLineChart from "./components/psiLineChart.vue";
// import coreBottomLeft from "./components/coreBottomLeft.vue";
// import orderProgress from "./components/orderProgress.vue";
// import keyWork from "./components/keyWork.vue";
import { getCostAnalysisXXCostList } from '@/api/cockpit'
import moment from "moment";
// import html2canvas from 'html2canvas'
// import JsPDF from 'jspdf'
@@ -88,37 +84,22 @@ export default {
},
data() {
return {
weekArr: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
isFullScreen: false,
timer: null,
beilv: 1,
value: 100,
coreProductVisualAlarmVO: [],
defect: {},
centerEqInfo: [
{ title: "工单数量", num: 0 },
{ title: "总产量/吨", num: 0 },
{ title: "生产合格率", num: "0%" },
{ title: "设备运行数量", num: 0 },
{ title: "累计能耗/kwh", num: 0 },
],
outputTrend: {},
coreProductVisualProcessVO: [],
coreProductVisualWorkOrderVO: {},
date: "",
weekDay: "", // 导出报表用
productNum: "",
coreProductVisualLineVO: [],
lineYieldVo: {}, // 产线良率
productionOverviewVo: [], // 生产状况
qualityDistributionVo: {}, // 本日不良分布
equipmentUtilizationVo: {}, // 设备性能稼动率
chipPowerDistributionVo: {}, // 芯片功率分布
modulePowerDistributionVo: {}, // 组件功率分布
chipPowerTrendVo: {},
modulePowerTrendVo: {},
equipmentProVo: [], // 表格
equipmentStateVo: [], // 设备状态分布
dateData: {},
levelId: 1,
pupList: [],
consumptionList: [],
dateData: {},
unitConsumptionList: [],
outputList: [],
analysisObject: [],
rawTypeList: [{
name: '原料成本',
id: 1,
}]
};
},
@@ -176,14 +157,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
this.loopTime();
console.log(1111);
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {
@@ -192,8 +165,57 @@ export default {
this.beilv = _this.clientWidth / 1920;
})();
};
if (this.$route.query.name) {
this.analysisObject = [this.$route.query.name]
} else {
this.analysisObject = ['原料成本']
}
},
methods: {
getData() {
// 基于选中的数据构建请求参数(根据实际接口需求调整)
// let analysisObject = []
const requestParams = {
// startTime: this.startTime,
// endTime: this.endTime,
// mode: this.mode,
startTime: 1762704000000,
endTime: 1762790400000,
mode: 1,
analysisObject: this.analysisObject,
levelId: this.levelId ? this.levelId : 1
};
// 调用接口
getCostAnalysisXXCostList(requestParams).then((res) => {
this.pupList = res.data[0]
this.consumptionList = res.data[1]
this.unitConsumptionList = res.data[2]
this.outputList = res.data[3]
});
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
handleGetData(data) {
console.log('从子组件接收的参数:', data);
// params中包含type和levelId
const { type, levelId } = data;
this.analysisObject = []
this.analysisObject.push(type)
this.levelId = levelId
// 在这里进行后续处理,如发起请求等
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
@@ -201,28 +223,6 @@ export default {
this.clientWidth = value;
this.beilv2 = this.clientWidth / 1920;
},
getToday8StartTimestamp() {
const date = new Date(); // 获取当前时间
// 将时设为8、分0、秒0、毫秒0
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
// 获取第二天早上八点的时间戳
getTomorrow8EndTimestamp() {
const date = new Date(); // 获取当前时间
// 先加一天,再设置为早上八点
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
loopTime() {
const _this = this;
_this.timer = setInterval(function () {
// _this.getData()
}, 60000);
},
change() {
this.isFullScreen = screenfull.isFullscreen;
},
@@ -259,16 +259,6 @@ export default {
}
screenfull.toggle(this.$refs.dayReportB);
},
changeDate(val) {
this.date = val;
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
if (this.date === moment().format("yyyy-MM-DD")) {
this.loopTime();
} else {
clearInterval(this.timer);
}
},
// 导出
// exportPDF() {
// this.$message.success('正在导出,请稍等!')

View File

@@ -2,7 +2,8 @@
<div id="dayReport" class="dayReport" :style="styles">
<div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar v-if="!sidebar.hide" class="sidebar-container" />
<ReportHeader size="psi" top-title="单项燃动力分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange" />
<ReportHeader size="psi" top-title="单项燃动力分析" :is-full-screen="isFullScreen" @screenfullChange="screenfullChange"
@timeRangeChange="handleTimeChange" />
<div class="main-body" style="
margin-top: -20px;
flex: 1;
@@ -16,7 +17,7 @@
gap: 12px;
grid-template-columns: 1624px;
">
<singleTopSelect typeName="燃动力" />
<singleTopSelect :defaultType="'燃动力成本'" :typeList="typeList" @query="handleGetData" typeName="燃动力" />
</div>
</div>
<div class="top" style="display: flex; gap: 16px;margin-top: 8px;">
@@ -25,8 +26,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<topLeftChart :name=" '采购单价·元/吨' " />
<topRightChart :name="'消耗量·吨'" />
<topLeftChart :dateData="dateData" :pupList="pupList" :name=" '采购单价·元/吨' " />
<topRightChart :dateData="dateData" :consumptionList="consumptionList" :name="'消耗量·吨'" />
</div>
</div>
@@ -36,8 +37,8 @@
gap: 12px;
grid-template-columns: 804px 804px;
">
<bottomLeftChart :name="'单耗趋势·吨/㎡'" />
<bottomLeftChart :name="'产量·㎡'" />
<bottomLeftChart :dateData="dateData" :unitConsumptionList="unitConsumptionList" :name="'单耗趋势·吨/㎡'" />
<bottomRightChart :dateData="dateData" :outputList="outputList" :name="'产量·㎡'" />
</div>
</div>
</div>
@@ -63,6 +64,7 @@ import topLeftChart from "./costComponents/single/topLeftChart.vue";
import topRightChart from "./costComponents/single/topRightChart.vue";
import bottomLeftChart from "./costComponents/single/bottomLeftChart.vue";
import bottomRightChart from "./costComponents/single/bottomRightChart.vue";
import { getCostAnalysisXXCostList } from '@/api/cockpit'
// import PSDO from "./components/PSDO.vue";
// import psiLineChart from "./components/psiLineChart.vue";
@@ -88,37 +90,22 @@ export default {
},
data() {
return {
weekArr: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
isFullScreen: false,
timer: null,
beilv: 1,
value: 100,
coreProductVisualAlarmVO: [],
defect: {},
centerEqInfo: [
{ title: "工单数量", num: 0 },
{ title: "总产量/吨", num: 0 },
{ title: "生产合格率", num: "0%" },
{ title: "设备运行数量", num: 0 },
{ title: "累计能耗/kwh", num: 0 },
],
outputTrend: {},
coreProductVisualProcessVO: [],
coreProductVisualWorkOrderVO: {},
date: "",
weekDay: "", // 导出报表用
productNum: "",
coreProductVisualLineVO: [],
lineYieldVo: {}, // 产线良率
productionOverviewVo: [], // 生产状况
qualityDistributionVo: {}, // 本日不良分布
equipmentUtilizationVo: {}, // 设备性能稼动率
chipPowerDistributionVo: {}, // 芯片功率分布
modulePowerDistributionVo: {}, // 组件功率分布
chipPowerTrendVo: {},
modulePowerTrendVo: {},
equipmentProVo: [], // 表格
equipmentStateVo: [], // 设备状态分布
dateData: {},
levelId: 1,
pupList: [],
consumptionList: [],
unitConsumptionList: [],
outputList: [],
dateData: {},
analysisObject: [],
typeList: [{
name: '燃动力成本',
id: 1,
}]
};
},
@@ -176,14 +163,6 @@ export default {
this.destroy();
},
mounted() {
const startTime = moment().startOf("week").format("YYYY-MM-DD");
const endTime = moment().format("YYYY-MM-DD");
console.log(this.date, "date");
this.date = [startTime, endTime];
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
this.loopTime();
console.log(1111);
const _this = this;
_this.beilv = document.documentElement.clientWidth / 1920;
window.onresize = () => {
@@ -192,8 +171,57 @@ export default {
this.beilv = _this.clientWidth / 1920;
})();
};
if (this.$route.query.name) {
this.analysisObject = [this.$route.query.name]
} else {
this.analysisObject = ['燃动力成本']
}
},
methods: {
getData() {
// 基于选中的数据构建请求参数(根据实际接口需求调整)
// let analysisObject = []
const requestParams = {
// startTime: this.startTime,
// endTime: this.endTime,
// mode: this.mode,
startTime: 1762704000000,
endTime: 1762790400000,
mode: 1,
analysisObject: this.analysisObject,
levelId: this.levelId ? this.levelId : 1
};
// 调用接口
getCostAnalysisXXCostList(requestParams).then((res) => {
this.pupList = res.data[0]
this.consumptionList = res.data[1]
this.unitConsumptionList = res.data[2]
this.outputList = res.data[3]
});
},
handleTimeChange(obj) {
console.log(obj, 'obj');
this.dateData = {
startTime: obj.startTime,
endTime: obj.endTime,
mode: obj.mode,
}
this.getData()
},
handleGetData(data) {
console.log('从子组件接收的参数:', data);
// params中包含type和levelId
const { type, levelId } = data;
this.analysisObject = []
this.analysisObject.push(type)
this.levelId = levelId
// 在这里进行后续处理,如发起请求等
if (this.dateData.startTime && this.dateData.endTime) {
this.getData();
}
},
handleClickOutside() {
this.$store.dispatch("app/closeSideBar", { withoutAnimation: false });
},
@@ -201,28 +229,6 @@ export default {
this.clientWidth = value;
this.beilv2 = this.clientWidth / 1920;
},
getToday8StartTimestamp() {
const date = new Date(); // 获取当前时间
// 将时设为8、分0、秒0、毫秒0
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
// 获取第二天早上八点的时间戳
getTomorrow8EndTimestamp() {
const date = new Date(); // 获取当前时间
// 先加一天,再设置为早上八点
date.setDate(date.getDate() + 1);
date.setHours(8, 0, 0, 0);
return date.getTime(); // 转换为时间戳(毫秒)
},
loopTime() {
const _this = this;
_this.timer = setInterval(function () {
// _this.getData()
}, 60000);
},
change() {
this.isFullScreen = screenfull.isFullscreen;
},
@@ -259,16 +265,6 @@ export default {
}
screenfull.toggle(this.$refs.dayReportB);
},
changeDate(val) {
this.date = val;
// this.weekDay = this.weekArr[moment(this.date).format('e')]
// this.getData()
if (this.date === moment().format("yyyy-MM-DD")) {
this.loopTime();
} else {
clearInterval(this.timer);
}
},
// 导出
// exportPDF() {
// this.$message.success('正在导出,请稍等!')