This commit is contained in:
李想 2025-04-25 17:00:21 +08:00
commit 65f6bdbd9c
34 changed files with 738 additions and 686 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -68,10 +68,8 @@ export default {
}
setOptions(option);
onMapClick(({ name, data }) => {
console.info('onMapClick点击区域:', name);
console.info('onMapClick关联数据:', data);
emit('click', { name, data });
onMapClick((data) => {
emit('click', data);
});
startAutoPlay({
interval: 2000,

View File

@ -33,7 +33,7 @@ export default {
emits: ['click'],
setup(props, { emit }) {
const chartRef = ref(null);
const { setOptions, getInstance, resize } = useEcharts(chartRef);
const { setOptions, getInstance, resize, onMapClick } = useEcharts(chartRef);
const option = reactive({
series: [],
});
@ -59,8 +59,11 @@ export default {
option.series = props.chartData;
setOptions(option);
resize();
getInstance()?.off('click', onClick);
getInstance()?.on('click', onClick);
onMapClick((data) => {
emit('click', data);
});
// getInstance()?.off('click', onClick);
// getInstance()?.on('click', onClick);
}
function onClick(params) {

View File

@ -1,6 +1,6 @@
<template>
<div class="dv-scroll-board">
<div v-if="status.header.length && status.mergedConfig" class="header" :style="`background-color: ${status.mergedConfig.headerBGC};`">
<div v-if="status.header.length && status.mergedConfig" class="header" :style="`background: ${status.mergedConfig.headerBGC};`">
<div
v-for="(headerItem, i) in status.header"
:key="`${headerItem}${i}`"
@ -23,7 +23,7 @@
:style="`
height: ${status.heights[ri]}px;
line-height: ${status.heights[ri]}px;
background-color: ${status.mergedConfig[row.rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']};
background: ${status.mergedConfig[row.rowIndex % 2 === 0 ? 'evenRowBGC' : 'oddRowBGC']};
`"
>
<div

View File

@ -111,21 +111,11 @@ export const useEcharts = (elRef, theme = 'default') => {
function handleMapClick(params) {
console.info('handleMapClick', params);
// 过滤非地图区域的点击事件
if (params.seriesType === 'map3D' || params.seriesType === 'map') {
// 获取点击区域信息
const mapName = params.name;
const regionData = params.data || {};
console.info('seriesType', params.seriesType);
// 执行注册的回调函数
if (typeof mapClickHandler === 'function') {
mapClickHandler({
name: mapName,
data: regionData,
coordinates: params.event?.event?.point,
// originalParams: params
});
}
// 执行注册的回调函数
if (typeof mapClickHandler === 'function') {
console.info('mapClickHandler', params);
mapClickHandler(params);
}
}

View File

@ -8,3 +8,7 @@
flex-direction: column;
}
}
.custom-echarts-tips {
color: #fff;
}

View File

@ -1,131 +0,0 @@
<template>
<div class="cases-alerts-warp">
<div class="cases-alerts" :style="{ 'background-image': 'url(' + getAssetsFile('images/inputs/partbg1.png') + ')' }">
<div class="cases-alerts-content">
<div class="cases-alerts-item-pos">
<template v-for="(n, index) in datalist" :key="index">
<div class="cases-alerts-item">
<div class="header" :style="{ 'background-image': 'url(' + getAssetsFile('images/inputs/partbg2.png') + ')' }">
<div class="title">{{ n.title }}</div>
</div>
<div class="content">
<template v-for="(m, mindex) in n.valStr" :key="mindex">
<div class="content-item" :style="{ 'background-image': 'url(' + getAssetsFile('images/inputs/partbg3.png') + ')' }">
<div class="num">{{ m }}</div>
</div>
</template>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { isEmpty, getAssetsFile } from '@/utils';
const datalist = reactive([
{ title: '案件次数', val: 100 },
{ title: '预警次数', val: 236 },
]);
onMounted(() => {
if (datalist.length && datalist.length > 0) {
datalist.forEach((m) => {
let valStr = '';
if (m.val < 1000 && m.val >= 100) {
valStr = '0' + m.val;
} else if (m.val < 100 && m.val >= 10) {
valStr = '00' + m.val;
} else if (m.val < 10) {
valStr = '000' + m.val;
} else {
valStr = m.val.toFixed(0);
}
m.valStr = [...valStr];
// console.info('valStr', m.valStr);
});
}
});
</script>
<style lang="scss" scoped>
div {
box-sizing: border-box;
}
.cases-alerts-warp {
height: 100%;
padding: 8px;
.cases-alerts {
width: 100%;
height: 100%;
background-size: 100% 100%;
background-repeat: no-repeat;
.cases-alerts-content {
width: 100%;
height: 100%;
padding: 0 20px;
display: inline-flex;
justify-content: center;
flex-direction: column;
.cases-alerts-item-pos {
width: 100%;
display: inline-flex;
justify-content: space-around;
}
.cases-alerts-item {
display: inline-block;
width: calc((100% - 20px) / 2);
.header,
.content {
display: inline-flex;
width: 100%;
}
.header {
background-size: 100% 100%;
background-repeat: no-repeat;
line-height: 32px;
height: 32px;
display: inline-block;
width: 100%;
.title {
text-align: center;
font-size: 16px;
font-weight: bold;
transform: skewX(-8deg);
background: linear-gradient(to bottom, '#ff7e5f', '#548fff');
-webkit-background-clip: text;
color: #fff;
letter-spacing: 8px;
text-shadow: -6px 0 0 1px #add8f1;
}
}
.content {
justify-content: space-around;
margin-top: 30%;
.content-item {
height: 36px;
display: inline-block;
width: calc((100% - 20px) / 4);
background-size: 100% 100%;
background-repeat: no-repeat;
line-height: 36px;
text-align: center;
.num {
text-align: center;
font-size: 20px;
font-weight: bold;
transform: skewX(-8deg);
background: linear-gradient(to bottom, '#ff7e5f', '#548fff');
-webkit-background-clip: text;
color: #fff;
text-shadow: -6px 0 0 1px #add8f1;
}
}
}
}
}
}
}
</style>

View File

@ -1,65 +0,0 @@
<template>
<div class="dealer-distribution-charts">
<custom-echart-bar :chart-data="chartsData.valData" height="100%" :option="chartsData.option" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
const chartsData = reactive({
option: {
grid: {
left: '3%',
right: '4%',
bottom: '2%',
top: '18%',
containLabel: true,
},
title: {
text: ' ',
textStyle: {
color: '#333',
},
},
label: {
color: '#333',
},
barStyle: {
barWidth: 15,
itemStyle: {
borderRadius: [8, 8, 0, 0], //
},
color: {
type: 'linear', // 线
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#45bfe9' },
{ offset: 1, color: '#01589c' },
],
global: false, // false
},
},
legend: {
show: false,
},
},
valData: [
{ value: 80, type: '经销商', name: '耿马镇' },
{ value: 105, type: '经销商', name: '勐撒镇' },
{ value: 100, type: '经销商', name: '勐永镇' },
{ value: 125, type: '经销商', name: '孟定镇' },
{ value: 217, type: '经销商', name: '勐简乡' },
{ value: 200, type: '经销商', name: '贺派乡' },
{ value: 155, type: '经销商', name: '四排山乡' },
{ value: 80, type: '经销商', name: '芒洪乡' },
{ value: 105, type: '经销商', name: '大兴乡' },
],
});
</script>
<style lang="scss" scoped>
.dealer-distribution-charts {
height: 100%;
}
</style>

View File

@ -0,0 +1,76 @@
<template>
<custom-echart-line ref="lineCharts" :chart-data="state.data" height="100%" :option="state.option" />
</template>
<script setup>
import { reactive, ref } from 'vue';
let dataList = [
{ value: 10, name: '2020' },
{ value: 66, name: '2021' },
{ value: 100, name: '2022' },
{ value: 120, name: '2023' },
{ value: 150, name: '2024' },
{ value: 80, name: '2025' },
];
const state = reactive({
option: {
color: ['#35D0C0'],
grid: {
left: '5%',
right: '5%',
bottom: '5%',
top: '10%',
containLabel: true,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
formatter: (data) => {
const params = data[0];
let str = `<div class="custom-echarts-tips">
<span>${params.name}</span><br/>
<span>${params.marker} ${params.data} 万元</span>
</div>`;
return str;
},
},
xAxis: {
type: 'category',
// name: '',
axisTick: {
show: false,
alignWithLabel: false,
interval: 'auto',
inside: false,
length: 5,
lineStyle: {
type: 'solid',
width: 1,
color: 'rgba(28, 158, 222, 1)',
},
},
},
yAxis: {
type: 'value',
// name: '',
},
},
data: dataList,
});
const lineCharts = ref(null);
const refresData = () => {
state.data = [
{ value: 5, name: '2020' },
{ value: 36, name: '2021' },
{ value: 70, name: '2022' },
{ value: 56, name: '2023' },
{ value: 70, name: '2024' },
{ value: 20, name: '2025' },
];
};
defineExpose({
refresData,
});
</script>

View File

@ -0,0 +1,284 @@
<template>
<custom-echart-pie-3d :chart-data="state.data" height="100%" :option="state.option" @click="handleClick" />
</template>
<script setup>
import { reactive, ref, onMounted, computed } from 'vue';
const state = reactive({
option: {},
data: [],
text: '',
});
const currentText = computed(() => state.text);
const pieData = [
{ value: 530, name: '种源企业', itemStyle: { color: '#8fd7fce8' } },
{ value: 1215, name: '肥料厂家', itemStyle: { color: '#466BE7e8' } },
{ value: 2312, name: '农药厂家', itemStyle: { color: '#F4BB29e8' } },
{ value: 916, name: '其他', itemStyle: { color: '#FF8329' } },
];
// series-surface.parametricEquation
function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
//
let midRatio = (startRatio + endRatio) / 2;
let startRadian = startRatio * Math.PI * 2;
let endRadian = endRatio * Math.PI * 2;
let midRadian = midRatio * Math.PI * 2;
//
if (startRatio === 0 && endRatio === 1) {
isSelected = false;
}
// / k 1/3
k = typeof k !== 'undefined' ? k : 1 / 3;
// x y 0
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
// 1
let hoverRate = isHovered ? 1.05 : 1;
//
return {
u: {
min: -Math.PI,
max: Math.PI * 3,
step: Math.PI / 32,
},
v: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20,
},
x: function (u, v) {
if (u < startRadian) {
return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: function (u, v) {
if (u < startRadian) {
return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: function (u, v) {
if (u < -Math.PI * 0.5) {
return Math.sin(u);
}
if (u > Math.PI * 2.5) {
return Math.sin(u) * h * 0.1;
}
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
},
};
}
function fomatFloat(num, n) {
var f = parseFloat(num);
if (isNaN(f)) {
return false;
}
f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n
var s = f.toString();
var rs = s.indexOf('.');
if (rs < 0) {
rs = s.length;
s += '.';
}
while (s.length <= rs + n) {
s += '0';
}
return s;
}
// 3d
function getHeight3D(series, height) {
series.sort((a, b) => {
return b.pieData.value - a.pieData.value;
});
return (height * 20) / series[0].pieData.value;
}
//
function getPie3D(pieData, internalDiameterRatio) {
let series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData = [];
let legendBfb = [];
let k = 1 - internalDiameterRatio;
pieData.sort((a, b) => {
return b.value - a.value;
});
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem = {
//
name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
type: 'surface',
//
parametric: true,
//线
wireframe: {
show: false,
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k,
},
//()
// center: ['50%', '100%']
};
//
if (typeof pieData[i].itemStyle != 'undefined') {
let itemStyle = {};
typeof pieData[i].itemStyle.color != 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null;
typeof pieData[i].itemStyle.opacity != 'undefined' ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null;
seriesItem.itemStyle = itemStyle;
}
series.push(seriesItem);
}
legendData = [];
legendBfb = [];
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value * 1;
series[i].pieData.startRatio = startValue / sumValue;
series[i].pieData.endRatio = endValue / sumValue;
series[i].parametricEquation = getParametricEquation(
series[i].pieData.startRatio,
series[i].pieData.endRatio,
false,
false,
k,
series[i].pieData.value
);
startValue = endValue;
let bfb = fomatFloat(series[i].pieData.value / sumValue, 4);
legendData.push({
name: series[i].name,
value: bfb,
});
legendBfb.push({
name: series[i].name,
value: bfb,
});
}
let boxHeight = getHeight3D(series, 15);
let option = {
legend: {
data: legendData,
color: ['#8FD7FC', '#466BE7', '#F4BB29', '#49C384', '#8FD7FC', '#466BE7', '#F4BB29', '#49C384'],
bottom: 10,
itemGap: 20,
show: true,
icon: 'rect',
itemHeight: 10,
itemWidth: 10,
textStyle: {
fontSize: 12,
color: '#B8DDFF',
lineHeight: 20,
},
// formatter: function (name) {
// var target;
// for (var i = 0, l = pieData.length; i < l; i++) {
// if (pieData[i].name == name) {
// target = pieData[i].value;
// }
// }
// return `${name} ${target}`;
// },
},
// title: {
// text: `{a|45%}{c|\n}`,
// x: 'center',
// y: 'center',
// textStyle: {
// rich: {
// a: {
// fontSize: 20,
// color: '#fff',
// },
// c: {
// fontSize: 12,
// color: '#fff',
// padding: [15, 0],
// },
// },
// },
// },
tooltip: {
show: false,
backgroundColor: 'rgba(18, 55, 85, 0.8);',
borderColor: 'transparent',
formatter: (params) => {
if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
let bfb = ((option.series[params.seriesIndex].pieData.endRatio - option.series[params.seriesIndex].pieData.startRatio) * 100).toFixed(2);
const value = option.series[params.seriesIndex].pieData.value;
return (
`<div style='color:rgba(214, 243, 255, 0.9);'>` +
`<span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>` +
`${params.seriesName}<br/>` +
`<span style='margin-right:20px'>${value}</span>` +
`<span >${bfb}%</span>` +
`</div>`
);
}
},
},
xAxis3D: {
min: -1,
max: 1,
},
yAxis3D: {
min: -1,
max: 1,
},
zAxis3D: {
min: -1,
max: 1,
},
grid3D: {
show: false,
boxHeight: boxHeight,
left: 0,
top: -30,
viewControl: {
alpha: 45, //( )
distance: 150, //zoom()
rotateSensitivity: 1, //0
zoomSensitivity: 1, //0
panSensitivity: 0, //0
autoRotate: true, //
},
},
series: series,
};
return option;
}
const handleClick = (params) => {
console.log(270, params);
// state.text = `{a|${params.dataIndex}%}{c|\n${params.seriesName}}`;
// currentText.value =
};
onMounted(() => {
const option = getPie3D(pieData, 0.8);
state.option = option;
state.data = option.series;
});
</script>

View File

@ -1,74 +0,0 @@
<template>
<div class="inputs-gmp-charts">
<custom-echart-pie :chart-data="chartsData.valData" height="100%" :option="chartsData.option" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
const chartsData = reactive({
option: {
color: ['#3685fe', '#41b879', '#ffd500'],
title: {
text: ' ',
textStyle: {
color: '#333',
},
},
legend: {
data: ['耿马镇', '勐撒镇', '勐永镇', '孟定镇', '勐简乡', '贺派乡', '四排山乡', '芒洪乡', '大兴乡'],
right: '0', // 10%
top: 'middle', //
orient: 'vertical', //
itemWidth: 15, //
itemHeight: 8, //
textStyle: {
fontSize: 10, //
color: '#fff', //
},
},
label: {
color: '#333',
},
series: [
{
type: 'pie',
radius: [20, 80],
roseType: 'area',
center: ['40%', '50%'],
label: {
show: false,
},
itemStyle: {
borderRadius: 5,
},
},
],
},
valData: [
{ value: 205, name: '耿马镇' },
{ value: 308, name: '勐撒镇' },
{ value: 359, name: '勐永镇' },
{ value: 452, name: '孟定镇' },
{ value: 388, name: '勐简乡' },
{ value: 508, name: '贺派乡' },
{ value: 369, name: '四排山乡' },
{ value: 610, name: '芒洪乡' },
{ value: 754, name: '大兴乡' },
],
});
onMounted(() => {
if (chartsData.valData && chartsData.valData.length) {
chartsData.valData.forEach((m, index) => {
let num = 100;
m.value = (Number(m.value) + Math.random() + num).toFixed(2);
});
}
});
</script>
<style lang="scss" scoped>
.inputs-gmp-charts {
height: 100%;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<centerMap :dialog-title="'土地类型'" @mapclick="doMapclick">
<centerMap :dialog-title="'投入品'" @mapclick="doMapclick">
<template #header>
<div class="land-map-pop-header">
<div class="title">{{ currentRegion && currentRegion.name ? currentRegion.name : '投入品' }}</div>
@ -18,9 +18,8 @@
</centerMap>
</template>
<script lang="ts" setup>
<script setup>
import { ref, reactive } from 'vue';
import centerMap from '@/components/centerMap.vue';
const unit = ref('家');
const list = reactive([
@ -32,9 +31,9 @@ const list = reactive([
{ title: '投入品规模', value: '3000', color: '#FC0003', unit: '万元' },
]);
let currentRegion = reactive(null);
let currentRegion = ref(null);
const doMapclick = (data) => {
currentRegion = data;
currentRegion.value = data;
};
</script>

View File

@ -0,0 +1,90 @@
<template>
<el-row :gutter="20">
<el-col v-for="item in state.list" :key="item.label" :span="12">
<div class="inputs-item flex-row">
<span class="inputs-item-icon">
<img :src="item.icon" />
</span>
<div class="inputs-item-info flex-column">
<b>{{ item.label }}</b>
<div class="inputs-item-value flex-row">
<em>{{ item.value }}</em>
<span>{{ item.unit }}</span>
</div>
</div>
</div>
</el-col>
</el-row>
</template>
<script setup>
import { reactive } from 'vue';
import { getAssetsFile } from '@/utils';
const state = reactive({
list: [
{
label: '监管机构',
value: 88,
unit: '家',
icon: getAssetsFile('images/inputs/1.png'),
},
{
label: '监管人员',
value: 106,
unit: '人',
icon: getAssetsFile('images/inputs/2.png'),
},
{
label: '村级监管员',
value: 38,
unit: '人',
icon: getAssetsFile('images/inputs/3.png'),
},
{
label: '农资经营单位',
value: 27,
unit: '家',
icon: getAssetsFile('images/inputs/4.png'),
},
{
label: '生产主体',
value: 154,
unit: '家',
icon: getAssetsFile('images/inputs/5.png'),
},
{
label: '检测机构',
value: 16,
unit: '家',
icon: getAssetsFile('images/inputs/6.png'),
},
],
});
</script>
<style lang="scss" scoped>
.inputs {
&-item {
align-items: center;
color: #fff;
padding: 10px 0;
&-icon {
margin-right: 16px;
}
&-info {
font-size: 16px;
font-weight: bold;
}
&-value {
margin-top: 10px;
justify-content: space-between;
em {
color: #02fd94;
font-style: normal;
}
}
}
}
</style>

View File

@ -0,0 +1,52 @@
<template>
<div class="board">
<custom-scroll-board :chart-config="options" />
</div>
</template>
<script setup>
import { ref } from 'vue';
const header = ['白名单企业', '产品名称', '黑名单企业', '产品名称'];
const len = header.length;
const options = ref({
attr: { w: 200, h: 240 },
option: {
header,
dataset: [
['富农种源', '京科824', '南方农业', '京科824'],
['富农种源', '京科824', '南方农业', '京科824'],
['富农种源', '京科824', '南方农业', '京科824'],
['富农种源', '京科824', '南方农业', '京科824'],
['富农种源', '京科824', '南方农业', '京科824'],
['富农种源', '京科824', '南方农业', '京科824'],
['富农种源', '京科824', '南方农业', '京科824'],
],
index: false,
columnWidth: [100, 100, 100, 100],
align: new Array(len).fill('center'),
rowNum: 5,
waitTime: 5,
headerHeight: 40,
carousel: 'single',
headerBGC: 'rgba(53, 208, 192, 0.4)',
oddRowBGC: 'rgba(0, 59, 81, 0.1)',
evenRowBGC: 'rgba(10, 39, 50, 0.1)',
},
});
</script>
<style scoped lang="scss">
.board {
padding: 10px 0px;
&:deep(.row-item) {
font-size: 16px;
.ceil {
&:nth-child(3),
&:nth-child(4) {
color: $color-danger;
}
}
}
}
</style>

View File

@ -0,0 +1,79 @@
<template>
<custom-echart-bar :chart-data="state.data" height="100%" :option="state.option" />
</template>
<script setup>
import { reactive } from 'vue';
const state = reactive({
option: {
grid: {
left: '5%',
right: '5%',
bottom: '5%',
top: '10%',
containLabel: true,
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
backgroundColor: 'rgba(18, 55, 85, 0.8);',
borderColor: '#35d0c0',
formatter: (data) => {
const params = data[0];
let str = `<div class="custom-echarts-tips">
<span>${params.name}</span><br/>
<span>${params.marker} ${params.data} 万元</span>
</div>`;
return str;
},
},
barStyle: {
barWidth: 15,
itemStyle: {
borderRadius: [8, 8, 0, 0],
},
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: '#35D0C0' },
{ offset: 1, color: '#35D0C0' },
],
global: false,
},
},
xAxis: {
type: 'category',
// name: '',
axisTick: {
show: false,
alignWithLabel: false,
interval: 'auto',
inside: false,
length: 5,
lineStyle: {
type: 'solid',
width: 1,
color: 'rgba(28, 158, 222, 1)',
},
},
},
yAxis: {
type: 'value',
// name: '()',
},
},
data: [
{ value: 530, name: '种子' },
{ value: 1215, name: '化肥' },
{ value: 2312, name: '农药' },
{ value: 916, name: '地膜' },
{ value: 108, name: '水' },
],
});
</script>

View File

@ -0,0 +1,83 @@
<template>
<div class="inputs">
<h2 class="inputs-title">检测批次15684</h2>
<el-row>
<el-col v-for="item in state.list" :key="item.label" :span="12">
<div class="inputs-item flex-column">
<div class="inputs-item-value">{{ item.value }}</div>
<div class="inputs-item-label">{{ item.label }}</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { reactive } from 'vue';
const state = reactive({
list: [
{
label: '检测合格率',
value: '98.99%',
},
{
label: '检测覆盖率',
value: '99.98%',
},
],
});
</script>
<style lang="scss" scoped>
.inputs {
&-title {
width: 240px;
height: 40px;
line-height: 40px;
margin: 24px auto 0;
background-image: url('@/assets/images/inputs/bg_title.png');
background-position: center bottom;
background-repeat: no-repeat;
background-size: 100%;
font-size: 20px;
color: #fff;
text-align: center;
text-shadow:
0 0 10px #01eeff,
0 0 20px #01eeff,
0 0 30px #01eeff,
0 0 40px #01eeff;
}
&-item {
&-label {
width: 120px;
height: 24px;
line-height: 24px;
margin: 0 auto 0;
background: url('@/assets/images/inputs/bg_label.png') center center no-repeat;
background-size: 100%;
font-size: 16px;
color: #fff;
text-align: center;
text-shadow:
0 0 10px #01eeff,
0 0 20px #01eeff,
0 0 30px #01eeff,
0 0 40px #01eeff;
}
&-value {
width: 160px;
height: 160px;
line-height: 180px;
text-align: center;
margin: 0 auto;
background-image: url('@/assets/images/inputs/bg_value.png');
background-size: 100%;
background-repeat: no-repeat;
font-size: 20px;
font-weight: 700;
color: #fff;
}
}
}
</style>

View File

@ -1,154 +0,0 @@
<template>
<div class="demo roll-list-land-plan" style="height: 100%" ref="refroll">
<!-- <div class="list-item-header item-warp" :style="{ flex: listKeys.length }">
<template v-for="(h, indexh) in listKeys" :key="indexh">
<div class="item-td" :style="{ width: 'calc(100% / ' + listKeys.length + ')' }">{{ listKeysHeader[h] }}</div>
</template>
</div> -->
<vue3ScrollSeamless class="scroll-wrap" :class-options="classOptions" :data-list="datalist">
<div v-for="(item, index) in datalist" :key="index" class="list-item">
<div class="list-item-content">
<div class="list-item-boday item-warp" :style="{ flex: listKeys.length }">
<div class="item-content">
<div class="label">{{ item.title }}</div>
<customProgress height="10px" :percent="item.percent"></customProgress>
</div>
</div>
</div>
</div>
</vue3ScrollSeamless>
</div>
<!-- </div> -->
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed, reactive } from 'vue';
import { vue3ScrollSeamless } from 'vue3-scroll-seamless';
import customProgress from '@/components/customProgress.vue';
const props = defineProps({
// items: {
// type: Array,
// default: () => [],
// },
});
let list = reactive([
{ title: '农药', value: 357 },
{ title: '肥料', value: 159 },
{ title: '种源', value: 516 },
{ title: '兽药', value: 82 },
{ title: '农机', value: 45 },
]);
let refroll = ref(null);
let datalist = computed(() => {
let maxwidth = refroll.value && refroll.value.clientWidth;
return list.map((m) => {
return {
...m,
percent: Number((Number(parseInt(m.value) / max.value) * 100).toFixed(0)),
pwidth: parseInt(Number(parseInt(m.value) / max.value) * maxwidth),
};
});
});
let max = computed(() => {
let valueList = new Set(list.map((item) => item.value));
let sortValue = [...valueList].sort((a, b) => b - a) || [];
// console.info('valueList', sortValue);
return sortValue.length ? sortValue[0] : 0;
});
const listKeys = reactive(['title', 'value']);
const listKeysHeader = reactive({
title: '分类',
value: '数量',
});
const classOptions = {
singleHeight: 48,
};
onMounted(() => {});
</script>
<style scoped lang="scss">
.roll-list-land-plan {
margin-top: 8px;
::v-deep() {
.el-progress-bar__outer {
background: transparent;
}
}
.scroll-wrap {
height: 90%;
width: 100%;
margin: 4px auto;
overflow: hidden;
}
.list-item-header {
background: #144482;
font-size: 10px;
width: 100%;
.item-td {
padding: 8px 6px;
}
}
.list-item-boday {
background: transparent;
width: 100%;
.item-td {
padding: 4px 6px;
&.td-title {
color: #6beff9 !important;
}
&.zebra-b {
background: #051225 !important;
}
}
}
.item-warp {
display: inline-flex;
justify-content: space-around;
.item-td {
display: inline-block;
vertical-align: middle;
text-align: center;
color: #fff;
}
.item-content {
width: 100%;
display: inline-flex;
justify-content: flex-start;
margin: 8px 0;
.label,
.val {
display: inline-block;
vertical-align: middle;
}
.label {
width: 50px;
color: #fff;
}
}
}
.list-item {
// border-bottom: 1px dashed rgba(255, 255, 255, 0.2);
line-height: 18px;
.list-item-content {
display: inline-flex;
width: 100%;
justify-content: space-around;
position: relative;
}
}
}
.demo {
// display: flex;
// align-items: center;
// justify-content: center;
// margin-top: 10px;
}
</style>

View File

@ -1,119 +0,0 @@
<template>
<div class="demo roll-list-land-plan" style="height: 90%">
<div class="list-item-header item-warp" :style="{ flex: listKeys.length }">
<template v-for="(h, indexh) in listKeys" :key="indexh">
<div class="item-td" :style="{ width: 'calc(100% / ' + listKeys.length + ')' }">{{ listKeysHeader[h] }}</div>
</template>
</div>
<vue3ScrollSeamless class="scroll-wrap" :class-options="classOptions" :data-list="list">
<div v-for="(item, index) in list" :key="index" class="list-item">
<div class="list-item-content">
<div class="list-item-boday item-warp" :style="{ flex: listKeys.length }">
<template v-for="(b, indexb) in listKeys" :key="indexb">
<div class="item-td" :class="{ 'zebra-b': (index + 1) % 2 == 0 }" :style="{ width: 'calc(100% / ' + listKeys.length + ')' }">
{{ item[b] }}
</div>
</template>
</div>
</div>
</div>
</vue3ScrollSeamless>
</div>
<!-- </div> -->
</template>
<script setup>
import { ref, onMounted, onUnmounted, computed, reactive } from 'vue';
import { vue3ScrollSeamless } from 'vue3-scroll-seamless';
const props = defineProps({
// items: {
// type: Array,
// default: () => [],
// },
});
let list = reactive([
{ title: '耿马镇', type: '吡虫啉', time: '2025.01.02', info: '经销商资质不合格' },
{ title: '勐撒镇', type: '多菌灵', time: '2025.01.01', info: '农药成分不合格' },
{ title: '孟定镇', type: '氯化钾', time: '2025.01.02', info: '经销商资质不合格' },
{ title: '孟简镇', type: 'NPK 复合肥', time: '2025.01.01', info: '成分不合格' },
{ title: '孟永镇', type: '青霉素', time: '2025.01.02', info: '经销商资质不合格' },
{ title: '大兴乡', type: '口蹄疫疫苗', time: '2025.01.01', info: '经销商资质不完全' },
{ title: '芒洪乡', type: '大豆种子', time: '2025.01.02', info: '种源质量不好' },
{ title: '四排山乡', type: '番茄种子', time: '2025.01.01', info: '经销商资质不合格' },
{ title: '贺派乡', type: '草甘膦', time: '2025.01.02', info: '农药成分不合格' },
]);
const listKeys = reactive(['title', 'type', 'time', 'info']);
const listKeysHeader = reactive({
title: '乡/镇',
type: '投入品种类',
time: '时间',
info: '案件信息',
});
const classOptions = {
singleHeight: 48,
};
</script>
<style scoped lang="scss">
.roll-list-land-plan {
margin-top: 8px;
.scroll-wrap {
height: 80%;
width: 100%;
margin: 4px auto;
overflow: hidden;
}
.list-item-header {
background: #144482;
font-size: 10px;
width: 100%;
.item-td {
padding: 8px 6px;
}
}
.list-item-boday {
background: transparent;
width: 100%;
.item-td {
padding: 4px 6px;
&.td-title {
color: #6beff9 !important;
}
&.zebra-b {
background: #051225 !important;
}
}
}
.item-warp {
display: inline-flex;
justify-content: space-around;
.item-td {
display: inline-block;
vertical-align: middle;
text-align: center;
color: #fff;
}
}
.list-item {
// border-bottom: 1px dashed rgba(255, 255, 255, 0.2);
line-height: 18px;
.list-item-content {
display: inline-flex;
width: 100%;
justify-content: space-around;
position: relative;
}
}
}
.demo {
// display: flex;
// align-items: center;
// justify-content: center;
// margin-top: 10px;
}
</style>

View File

@ -1,99 +0,0 @@
<template>
<div class="monthly-use-charts">
<custom-echart-line-line :chart-data="chartsData.valData" height="100%" :option="chartsData.option" />
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
const chartsData = reactive({
option: {
grid: {
left: '3%',
right: '4%',
bottom: '2%',
top: '18%',
containLabel: true,
},
// color: ['#3685fe', '#41b879', '#fed500'],
title: {
text: ' ',
textStyle: {
color: '#333',
},
},
legend: {
right: '0', // 10%
top: '0', //
itemWidth: 15, //
itemHeight: 8, //
textStyle: {
fontSize: 10, //
color: '#fff', //
},
data: ['农药', '肥料', '种源', '兽药', '农机'],
},
xAxis: {
type: 'category',
name: ' ',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
},
yAxis: {
type: 'value',
name: '',
axisLine: {
show: true,
lineStyle: {
color: '#BAE7FF',
width: 1,
type: 'solid',
},
},
splitLine: {
lineStyle: {
color: 'rgba(186, 231, 255, 0.2)',
type: 'dashed',
},
},
axisLabel: {
show: true,
textStyle: {
color: 'white',
},
},
},
series: [
{
name: '农药',
type: 'line',
data: [120, 132, 101, 134, 90, 230, 210, 500, 600, 200, 300, 150],
},
{
name: '肥料',
type: 'line',
data: [485, 182, 353, 265, 290, 354, 215, 200, 158, 600, 158, 320],
},
{
name: '种源',
type: 'line',
data: [120, 516, 238, 453, 368, 519, 432, 128, 578, 120, 578, 324],
},
{
name: '兽药',
type: 'line',
data: [120, 132, 101, 134, 90, 230, 210, 500, 600, 565, 134, 256],
},
{
name: '农机',
type: 'line',
data: [485, 182, 353, 265, 290, 354, 215, 200, 158, 326, 456, 189],
},
],
},
});
</script>
<style lang="scss" scoped>
.monthly-use-charts {
height: 100%;
}
</style>

View File

@ -4,21 +4,21 @@
<div class="left-charts-item">
<customBack top-title="投入品监管体系建设" :top-postion="'left'">
<template #back>
<inputsType></inputsType>
<inputsOne />
</template>
</customBack>
</div>
<div class="left-charts-item">
<customBack top-title="投入品检测监管" :top-postion="'left'">
<template #back>
<inputsGmp></inputsGmp>
<inputsTwo />
</template>
</customBack>
</div>
<div class="left-charts-item">
<customBack top-title="农资监管" :top-postion="'left'">
<customBack top-title="投入品金额对比" :top-postion="'left'">
<template #back>
<landbreedCharts></landbreedCharts>
<inputsThere />
</template>
</customBack>
</div>
@ -30,21 +30,41 @@
<div class="right-charts-item">
<customBack top-title="生产主体统计" :top-postion="'right'">
<template #back>
<casesAlerts></casesAlerts>
<inputsFour />
</template>
</customBack>
</div>
<div class="right-charts-item">
<customBack top-title="历年投入品规模对比" :top-postion="'right'">
<customBack
top-title="历年投入品规模对比"
:top-postion="'right'"
:down-title="'全县'"
:label-field="'label'"
:value-field="'value'"
:down-width="'100px'"
:options="[
{ label: '全县', value: '530926' },
{ label: '耿马镇', value: '42611' },
{ label: '勐撒镇', value: '9259' },
{ label: '勐永镇', value: '17787' },
{ label: '孟定镇', value: '42610' },
{ label: '勐简乡', value: '17788' },
{ label: '贺派乡', value: '40161' },
{ label: '四排山乡', value: '40163' },
{ label: '大兴乡', value: '40159' },
]"
:is-down="true"
@command="handleCommand"
>
<template #back>
<monthlyuseCharts></monthlyuseCharts>
<!-- <inputsFive ref="fiveRef" /> -->
</template>
</customBack>
</div>
<div class="right-charts-item">
<customBack top-title="投入品白名单/黑名单" :top-postion="'right'">
<template #back>
<dealerDistributionCharts></dealerDistributionCharts>
<!-- <inputsSix /> -->
</template>
</customBack>
</div>
@ -52,14 +72,22 @@
</el-row>
</template>
<script setup>
import centerMap from '@/components/centerMap.vue';
import inputsGmp from './components/inputsGmp.vue';
import landbreedCharts from './components/landbreedCharts.vue';
import monthlyuseCharts from './components/monthlyuseCharts.vue';
import dealerDistributionCharts from './components/dealerDistributionCharts.vue';
import casesAlerts from './components/casesAlerts.vue';
import inputsType from './components/inputsType.vue';
import inputsOne from './components/inputsOne.vue';
import inputsTwo from './components/inputsTwo.vue';
import inputsThere from './components/inputsThere.vue';
import inputsFour from './components/inputsFour.vue';
import inputsFive from './components/inputsFive.vue';
import inputsSix from './components/inputsSix.vue';
import inputsMap from './components/inputsMap.vue';
import { nextTick, ref } from 'vue';
const fiveRef = ref(null);
const handleCommand = (data) => {
console.info('data=', data);
nextTick(() => {
fiveRef.value && fiveRef.value.refresData();
});
};
</script>
<style lang="scss" scoped>
.data-home-index {

View File

@ -18,6 +18,8 @@ const state = reactive({
axisPointer: {
type: 'shadow',
},
backgroundColor: 'rgba(18, 55, 85, 0.8);',
borderColor: '#35d0c0',
formatter: (data) => {
const params = data[0];
let str = `<div class="custom-echarts-tips">

View File

@ -55,6 +55,10 @@ const options = ref({
font-family: 'DingTalk JinBuTi, DingTalk JinBuTi-Regular';
font-weight: 700;
}
.inside-column {
border-radius: 8px;
}
}
&:deep(.row-item-1) {

View File

@ -26,6 +26,8 @@ const state = reactive({
axisPointer: {
type: 'shadow',
},
backgroundColor: 'rgba(18, 55, 85, 0.8);',
borderColor: '#35d0c0',
formatter: (data) => {
const params = data[0];
let str = `<div class="custom-echarts-tips">