feat(dashboard): 控制台剖析图表支持指标国标维度分类切换、去除厚重大色块并启用动态自适应刻度
这个提交包含在:
@@ -77,27 +77,48 @@
|
||||
|
||||
<!-- 仓库农作检测参数数据折线图 -->
|
||||
<el-row class="row main">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="main-1">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="main-position">
|
||||
<div class="main-refresh">
|
||||
<div class="refresh-btn">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="main-1" style="background: #ffffff; border-radius: 8px; box-shadow: 0 1px 4px rgba(0,21,41,0.08); overflow: hidden;">
|
||||
<style>
|
||||
.custom-dashboard-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 14px 20px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
.category-filter-bar {
|
||||
padding: 10px 20px;
|
||||
background: #fafbfc;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
<!-- 顶部筛选栏 -->
|
||||
<div class="custom-dashboard-bar">
|
||||
<div class="main-refresh" style="display: flex; align-items: center;">
|
||||
<div class="refresh-btn" @click="getParamsLineCharts" style="cursor: pointer; display: flex; align-items: center; gap: 4px; color: #409eff; font-size: 14px;">
|
||||
<i class="el-icon-refresh-right"></i>
|
||||
<span class="main-refresh-tip theme-color-1">刷新图表</span>
|
||||
<span class="main-refresh-tip" style="font-weight: 500;">刷新图表</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="main-position-right">
|
||||
<div class="main-position-right" style="display: flex; align-items: center; flex-wrap: wrap; gap: 10px;">
|
||||
<div class="search-date">
|
||||
<el-date-picker
|
||||
size="small"
|
||||
value-format="yyyy"
|
||||
style="width: 220px;"
|
||||
style="width: 140px;"
|
||||
v-model="search.year"
|
||||
type="year"
|
||||
placeholder="检测年份">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="granary" style="margin-left: 10px;">
|
||||
<el-select filterable size="small" style="width: 270px;" v-model="search.gid" placeholder="所属仓库" @change="granaryChange">
|
||||
<div class="granary">
|
||||
<el-select filterable size="small" style="width: 200px;" v-model="search.gid" placeholder="所属仓库" @change="granaryChange">
|
||||
<el-option
|
||||
v-for="item in granaryList"
|
||||
:key="item.id"
|
||||
@@ -106,21 +127,37 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="type-list" style="margin-left: 10px;position: relative;top: -6px;">
|
||||
<div class="screen-container-right display-flex" style="position: relative; top: 2px;">
|
||||
<el-radio-group size="small" v-model="search.type" @change="typeChange">
|
||||
<el-radio-button v-for="(item, index) of typeList" :label="index">{{item.name}}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="type-list">
|
||||
<el-radio-group size="small" v-model="search.type" @change="typeChange">
|
||||
<el-radio-button v-for="(item, index) of typeList" :label="index">{{item.name}}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="search-btn">
|
||||
<el-button @click="getParamsLineCharts" size="small" type="primary" plain icon="el-icon-search">查询
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<div class="chart-data">
|
||||
</div>
|
||||
<!-- 指标分类维度专属切换条 -->
|
||||
<div class="category-filter-bar">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<span style="font-size: 13px; color: #4b5563; margin-right: 12px; font-weight: 600;">
|
||||
<i class="el-icon-s-operation" style="color: #409eff;"></i> 指标维度:
|
||||
</span>
|
||||
<el-radio-group size="mini" v-model="selectedCategory" @change="categoryChange">
|
||||
<el-radio-button label="core">⭐ 核心品质</el-radio-button>
|
||||
<el-radio-button label="impurity">🌾 物理与杂质</el-radio-button>
|
||||
<el-radio-button label="storage">🧪 储存品质</el-radio-button>
|
||||
<el-radio-button label="safety">🛡️ 卫生安全</el-radio-button>
|
||||
<el-radio-button label="all">📊 全部指标</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div style="font-size: 12px; color: #909399;">
|
||||
<i class="el-icon-info"></i> 已按国标体系分类,Y轴动态自适应放大微量指标
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-data" style="padding: 10px 10px 0 10px;">
|
||||
<div style="height: 520px;" id="main-chart"></div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
@@ -4,7 +4,7 @@ return array (
|
||||
'name' => '中央储备粮遵义直属库有限公司',
|
||||
'beian' => '',
|
||||
'cdnurl' => '',
|
||||
'version' => '20261102_v3',
|
||||
'version' => '20261102_v6',
|
||||
'timezone' => 'Asia/Shanghai',
|
||||
'forbiddenip' => '',
|
||||
'languages' =>
|
||||
|
||||
@@ -1,5 +1,38 @@
|
||||
define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echarts-theme', 'template'], function ($, undefined, Backend, Datatable, Table, Echarts, undefined, Template) {
|
||||
|
||||
var CATEGORY_DEFS = {
|
||||
core: {
|
||||
name: '核心品质',
|
||||
keywords: ['水分', '整精米率', '容重', '出糙率', '色泽', '气味', '纯粮率']
|
||||
},
|
||||
impurity: {
|
||||
name: '物理与杂质',
|
||||
keywords: ['杂质', '黄粒米', '谷外糙米', '互混', '不完善粒', '生霉粒', '加热损伤粒']
|
||||
},
|
||||
storage: {
|
||||
name: '储存品质',
|
||||
keywords: ['脂肪酸值', '面筋吸水量', '品尝评分', '酸价', '过氧化值', '发芽率', '还原糖']
|
||||
},
|
||||
safety: {
|
||||
name: '卫生安全',
|
||||
keywords: ['铅', '镉', '总汞', '汞', '无机砷', '砷', '黄曲霉毒素', '黄曲霉毒素B1', '马拉硫磷', '农药']
|
||||
}
|
||||
};
|
||||
|
||||
function filterSeriesByCategory(seriesData, categoryKey) {
|
||||
if (!seriesData || !Array.isArray(seriesData)) return [];
|
||||
if (!categoryKey || categoryKey === 'all') return seriesData;
|
||||
var cat = CATEGORY_DEFS[categoryKey];
|
||||
if (!cat) return seriesData;
|
||||
return seriesData.filter(function (item) {
|
||||
var name = item.name || '';
|
||||
return cat.keywords.some(function (kw) {
|
||||
return name.indexOf(kw) !== -1;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
var vue = new Vue({
|
||||
@@ -8,6 +41,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
lineCharts: [],
|
||||
granaryList: [],
|
||||
typeList: [],
|
||||
selectedCategory: 'core',
|
||||
search: {
|
||||
gid: '',
|
||||
year: '',
|
||||
@@ -18,6 +52,9 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
this.getInitData();
|
||||
},
|
||||
methods: {
|
||||
categoryChange(cat) {
|
||||
this.paramsLineCharts();
|
||||
},
|
||||
// 仓库切换智能联动其品种并刷新折线图
|
||||
granaryChange(gid) {
|
||||
let cur = this.granaryList.find(function (item) { return item.id === gid; });
|
||||
@@ -96,19 +133,38 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
}
|
||||
})
|
||||
},
|
||||
// 折线图
|
||||
// 折线图 (平滑无遮挡 + 指标分类过滤 + 自适应刻度)
|
||||
paramsLineCharts() {
|
||||
let series = this.lineCharts || {};
|
||||
let lineChart = Echarts.init(document.getElementById('main-chart'));
|
||||
let legendData = [];
|
||||
let hasData = false;
|
||||
|
||||
if (series.seriesData && series.seriesData.length) {
|
||||
for (let i = 0; i < series.seriesData.length; i++) {
|
||||
let item = series.seriesData[i];
|
||||
let rawSeriesData = (series.seriesData && Array.isArray(series.seriesData)) ? series.seriesData : [];
|
||||
let displaySeries = filterSeriesByCategory(rawSeriesData, this.selectedCategory);
|
||||
if (!displaySeries.length && this.selectedCategory !== 'all' && rawSeriesData.length) {
|
||||
displaySeries = [];
|
||||
}
|
||||
|
||||
if (displaySeries && displaySeries.length) {
|
||||
for (let i = 0; i < displaySeries.length; i++) {
|
||||
let item = displaySeries[i];
|
||||
item.type = 'line';
|
||||
item.areaStyle = {
|
||||
focus: 'series'
|
||||
item.smooth = true;
|
||||
item.symbol = 'circle';
|
||||
item.symbolSize = 7;
|
||||
delete item.areaStyle;
|
||||
item.lineStyle = {
|
||||
width: 2.5
|
||||
};
|
||||
item.label = {
|
||||
show: true,
|
||||
position: 'top',
|
||||
fontSize: 11,
|
||||
color: '#4b5563',
|
||||
formatter: function (p) {
|
||||
return (p.value !== 0 && p.value !== '0' && p.value !== null && p.value !== undefined) ? p.value : '';
|
||||
}
|
||||
};
|
||||
legendData.push(item.name);
|
||||
if (item.data && item.data.length && item.data.some(function (v) { return v !== null && v !== undefined && v !== ''; })) {
|
||||
@@ -122,11 +178,19 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
let granaryName = curGranary ? curGranary.name : '所选仓库';
|
||||
let typeName = this.typeList && this.typeList[this.search.type] ? this.typeList[this.search.type].name : this.search.type;
|
||||
let yearText = this.search.year || '';
|
||||
let currentCatName = (CATEGORY_DEFS[this.selectedCategory] ? CATEGORY_DEFS[this.selectedCategory].name : '指标');
|
||||
|
||||
let emptySubtext = '';
|
||||
if (!rawSeriesData.length) {
|
||||
emptySubtext = (yearText ? yearText + '年 ' : '') + granaryName + ' 暂无【' + typeName + '】检测报告,可切换年份或对应品种查看';
|
||||
} else {
|
||||
emptySubtext = (yearText ? yearText + '年 ' : '') + granaryName + '【' + typeName + '】暂无【' + currentCatName + '】项检测数据,可切换其他分类或全部指标查看';
|
||||
}
|
||||
|
||||
let option = {
|
||||
title: !hasData ? {
|
||||
text: '暂无检测数据',
|
||||
subtext: (yearText ? yearText + '年 ' : '') + granaryName + ' 暂无【' + typeName + '】检测报告,可切换年份或对应品种查看',
|
||||
subtext: emptySubtext,
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
textStyle: {
|
||||
@@ -143,6 +207,13 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: '#e4e7ed',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: '#303133',
|
||||
fontSize: 12
|
||||
},
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
label: {
|
||||
@@ -151,7 +222,12 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: hasData ? legendData : []
|
||||
data: hasData ? legendData : [],
|
||||
top: 5,
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
color: '#606266'
|
||||
}
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
@@ -159,24 +235,49 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'table', 'echarts', 'echart
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
left: '4%',
|
||||
right: '4%',
|
||||
bottom: 0,
|
||||
top: 50,
|
||||
bottom: 20,
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: hasData ? (series.list || []) : []
|
||||
data: hasData ? (series.list || []) : [],
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#dcdfe6'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#606266'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value'
|
||||
type: 'value',
|
||||
scale: true,
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#dcdfe6'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#606266'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#f2f3f5'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: hasData ? series.seriesData : []
|
||||
series: hasData ? displaySeries : []
|
||||
};
|
||||
|
||||
lineChart.setOption(option, true);
|
||||
|
||||
在新工单中引用
屏蔽一个用户