Merge branch 'main' of http://47.109.205.240:3000/Web/digital-agriculture-screen
This commit is contained in:
commit
50cc309c18
@ -54,14 +54,14 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default() {
|
||||
return [
|
||||
{ label: '首页', value: 'home' },
|
||||
{ label: '土地资源', value: 'land' },
|
||||
{ label: '投入品监管', value: 'inputs' },
|
||||
{ label: '产出品管理', value: 'entities' },
|
||||
{ label: '首页', value: '/v2/home' },
|
||||
{ label: '土地资源', value: '/v2/land' },
|
||||
{ label: '投入品监管', value: '/v2/inputs' },
|
||||
{ label: '产出品管理', value: '/v2/entities' },
|
||||
// { label: '智慧种植监测', value: 'plant' },
|
||||
// { label: '智慧养殖监测', value: 'breed' },
|
||||
{ label: '生产经营主体', value: 'business' },
|
||||
{ label: '农产品溯源', value: 'trace' },
|
||||
{ label: '生产经营主体', value: '/v2/business' },
|
||||
{ label: '农产品溯源', value: '/v2/trace' },
|
||||
// { label: '产业预警决策', value: 'early' },
|
||||
];
|
||||
},
|
||||
@ -122,7 +122,7 @@ function handleTitleBtn(t = -1) {
|
||||
function handleTitleClick(val) {
|
||||
activeTitle.value = val;
|
||||
// emit('changeTitle', val);
|
||||
router.push({ name: val });
|
||||
router.push({ path: val });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -20,13 +20,13 @@ export default {
|
||||
meta: { title: '土地资源', icon: '' },
|
||||
},
|
||||
{
|
||||
path: 'inputs',
|
||||
path: '/v2/inputs',
|
||||
name: 'inputs',
|
||||
component: () => import('@/views/inputs/index.vue'),
|
||||
meta: { title: '投入品监管', icon: '' },
|
||||
},
|
||||
{
|
||||
path: 'entities',
|
||||
path: '/v2/entities',
|
||||
name: 'entities',
|
||||
component: () => import('@/views/entities/index.vue'),
|
||||
meta: { title: '产出品管理', icon: '' },
|
||||
@ -44,7 +44,7 @@ export default {
|
||||
// meta: { title: '', icon: '' },
|
||||
// },
|
||||
{
|
||||
path: 'business',
|
||||
path: '/v2/business',
|
||||
name: 'business',
|
||||
component: () => import('@/views/business/index.vue'),
|
||||
meta: { title: '生产经营主体', icon: '' },
|
||||
|
109
src/views/business/components/businessFive.vue
Normal file
109
src/views/business/components/businessFive.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="rank">
|
||||
<custom-rank-List :chart-config="state" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue';
|
||||
import { isEmpty } from '@/utils';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
attr: { w: '100%', h: 240 },
|
||||
option: {
|
||||
// 数据
|
||||
dataset: [],
|
||||
type: 'column',
|
||||
rowNum: 6,
|
||||
isAnimation: true,
|
||||
waitTime: 5,
|
||||
unit: '万元',
|
||||
sort: true,
|
||||
height: 12,
|
||||
color: 'linear-gradient(90deg,rgba(53,208,192,0.00), #35d0c0)',
|
||||
textColor: '#fff',
|
||||
borderRadius: '12px',
|
||||
carousel: 'single',
|
||||
indexPrefix: 'TOP',
|
||||
indexFontSize: 12,
|
||||
leftFontSize: 14,
|
||||
rightFontSize: 14,
|
||||
valueFormatter: (item) => {
|
||||
return item.value;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (!isEmpty(val)) {
|
||||
state.option.dataset = val;
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.rank {
|
||||
padding: 10px 20px;
|
||||
|
||||
&:deep(.row-item) {
|
||||
.ranking-info {
|
||||
color: #35d0c0 !important;
|
||||
font-family: 'DingTalk JinBuTi, DingTalk JinBuTi-Regular';
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.inside-column {
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&:deep(.row-item-1) {
|
||||
.ranking-info {
|
||||
color: #fe7f03 !important;
|
||||
}
|
||||
.ranking-value {
|
||||
color: #fe7f03 !important;
|
||||
}
|
||||
.inside-column {
|
||||
background: linear-gradient(90deg, rgba(254, 127, 3, 0), #fe7f03) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:deep(.row-item-2) {
|
||||
.ranking-info {
|
||||
color: #fef906 !important;
|
||||
}
|
||||
.ranking-value {
|
||||
color: #fef906 !important;
|
||||
}
|
||||
.inside-column {
|
||||
background: linear-gradient(90deg, rgba(254, 249, 6, 0), #fef906) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:deep(.row-item-3) {
|
||||
.ranking-info {
|
||||
color: #02fd94 !important;
|
||||
}
|
||||
.ranking-value {
|
||||
color: #02fd94 !important;
|
||||
}
|
||||
.inside-column {
|
||||
background: linear-gradient(90deg, rgba(2, 253, 148, 0), #02fd94) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
78
src/views/business/components/businessFour.vue
Normal file
78
src/views/business/components/businessFour.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="business">
|
||||
<custom-echart-water-droplet width="100%" height="100%" :option="option" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
let percent = ref(0.6);
|
||||
const option = ref({
|
||||
backgroundColor: 'transparent', //背景色
|
||||
series: [
|
||||
{
|
||||
name: '预估量',
|
||||
type: 'liquidFill',
|
||||
radius: '80%',
|
||||
center: ['50%', '50%'],
|
||||
backgroundStyle: {
|
||||
color: 'transparent',
|
||||
},
|
||||
data: [percent.value, percent.value],
|
||||
amplitude: 12, //水波振幅
|
||||
label: {
|
||||
//标签设置
|
||||
position: ['50%', '45%'],
|
||||
formatter: percent.value * 100 + '%', //显示文本,
|
||||
textStyle: {
|
||||
fontSize: '20px', //文本字号,
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
outline: {
|
||||
borderDistance: 3,
|
||||
itemStyle: {
|
||||
borderWidth: 1,
|
||||
borderColor: {
|
||||
type: 'linear',
|
||||
x: 1,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 0,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
},
|
||||
{
|
||||
offset: 0.6,
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
},
|
||||
],
|
||||
globalCoord: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'linear', // 线性渐变
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: '#45bfe9' },
|
||||
{ offset: 1, color: '#01589c' },
|
||||
],
|
||||
global: false, // 默认为 false
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
302
src/views/business/components/businessOne.vue
Normal file
302
src/views/business/components/businessOne.vue
Normal file
@ -0,0 +1,302 @@
|
||||
<template>
|
||||
<custom-echart-pie-3d :chart-data="state.data" height="100%" :option="state.option" />
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue';
|
||||
import { isEmpty } from '@/utils';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
option: {},
|
||||
data: [],
|
||||
text: '',
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
legendSuffix: '%',
|
||||
legend: {
|
||||
data: legendData,
|
||||
// color: ['#8FD7FC', '#466BE7', '#F4BB29', '#49C384', '#8FD7FC', '#466BE7', '#F4BB29', '#49C384'],
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
itemGap: 20,
|
||||
show: true,
|
||||
icon: 'rect',
|
||||
itemHeight: 16,
|
||||
itemWidth: 16,
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: '#B8DDFF',
|
||||
lineHeight: 20,
|
||||
},
|
||||
formatter: (name) => {
|
||||
if (state.data.length) {
|
||||
const item = state.data.filter((item) => item.name === name)[0];
|
||||
return `${name} ${item.pieData.value}${state.option.legendSuffix ?? ''}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: 'rgba(18, 55, 85, 0.8);',
|
||||
borderColor: '#35d0c0',
|
||||
color: '#fff',
|
||||
position: function (point, params, dom, rect, size) {
|
||||
var x = point[0];
|
||||
var y = point[1];
|
||||
var viewWidth = size.viewSize[0];
|
||||
var viewHeight = size.viewSize[1];
|
||||
var boxWidth = size.contentSize[0];
|
||||
var boxHeight = size.contentSize[1];
|
||||
// 判断 tooltip 位置,调整其位置使其不会超出图表边界
|
||||
if (x + boxWidth > viewWidth) {
|
||||
x = x - boxWidth;
|
||||
}
|
||||
if (y + boxHeight > viewHeight) {
|
||||
y = y - boxHeight;
|
||||
}
|
||||
// 保证 tooltip 始终在图表内部
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
|
||||
return [x, y];
|
||||
},
|
||||
formatter: (params) => {
|
||||
if (params.seriesName !== 'mouseoutSeries') {
|
||||
return `
|
||||
<span style="color:#FFF">
|
||||
${params.seriesName}<br/>
|
||||
<span style="display:inline-block;
|
||||
margin-right:5px;
|
||||
border-radius:10px;
|
||||
width:10px;
|
||||
height:10px;
|
||||
background-color:${params.color};"></span>
|
||||
${option.series[params.seriesIndex].pieData.value}
|
||||
</span>
|
||||
`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
},
|
||||
xAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
yAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
zAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
grid3D: {
|
||||
show: false,
|
||||
boxHeight: boxHeight,
|
||||
left: '-20%',
|
||||
top: -20,
|
||||
viewControl: {
|
||||
alpha: 30, //角度(这个很重要 调节角度的)
|
||||
distance: 150, //调整视角到主体的距离,类似调整zoom(这是整体大小)
|
||||
rotateSensitivity: 1, //设置为0无法旋转
|
||||
zoomSensitivity: 0, //设置为0无法缩放
|
||||
panSensitivity: 0, //设置为0无法平移
|
||||
autoRotate: true, //自动旋转
|
||||
},
|
||||
},
|
||||
series: series,
|
||||
};
|
||||
return option;
|
||||
}
|
||||
|
||||
const initData = (pieData = []) => {
|
||||
const option = getPie3D(pieData, 0.8);
|
||||
state.option = option;
|
||||
state.data = option.series;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (!isEmpty(val)) {
|
||||
const pieData = val.map((row) => {
|
||||
return {
|
||||
name: row.name,
|
||||
value: row.value,
|
||||
};
|
||||
});
|
||||
initData(pieData);
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
274
src/views/business/components/businessSix.vue
Normal file
274
src/views/business/components/businessSix.vue
Normal file
@ -0,0 +1,274 @@
|
||||
<template>
|
||||
<custom-echart-pie-3d :chart-data="state.data" height="100%" :option="state.option" @click="handleClick" />
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue';
|
||||
import { isEmpty } from '@/utils';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
option: {},
|
||||
data: [],
|
||||
text: '',
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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'],
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
itemGap: 20,
|
||||
show: true,
|
||||
icon: 'rect',
|
||||
itemHeight: 16,
|
||||
itemWidth: 16,
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: '#B8DDFF',
|
||||
lineHeight: 20,
|
||||
},
|
||||
},
|
||||
title: {
|
||||
text: '',
|
||||
x: '35%',
|
||||
y: '30%',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 20,
|
||||
color: '#fff',
|
||||
},
|
||||
c: {
|
||||
fontSize: 12,
|
||||
color: '#fff',
|
||||
padding: [15, 0],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
yAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
zAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
grid3D: {
|
||||
show: false,
|
||||
boxHeight: boxHeight,
|
||||
left: '-10%',
|
||||
top: -20,
|
||||
viewControl: {
|
||||
alpha: 55, //角度(这个很重要 调节角度的)
|
||||
distance: 150, //调整视角到主体的距离,类似调整zoom(这是整体大小)
|
||||
rotateSensitivity: 1, //设置为0无法旋转
|
||||
zoomSensitivity: 0, //设置为0无法缩放
|
||||
panSensitivity: 0, //设置为0无法平移
|
||||
autoRotate: true, //自动旋转
|
||||
},
|
||||
},
|
||||
series: series,
|
||||
};
|
||||
return option;
|
||||
}
|
||||
|
||||
const initData = (pieData = []) => {
|
||||
const option = getPie3D(pieData, 0.8);
|
||||
const { name, value } = option.series[0].pieData;
|
||||
option.title.text = `{a|${value}%}{c|\n${name}}`;
|
||||
state.option = option;
|
||||
state.data = option.series;
|
||||
};
|
||||
|
||||
const handleClick = (params) => {
|
||||
const findItem = state.data.find((el) => el.name === params.seriesName);
|
||||
state.option.title.text = `{a|${findItem?.pieData?.value}%}{c|\n${params.seriesName}}`;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (!isEmpty(val)) {
|
||||
const pieData = val.map((row) => {
|
||||
return {
|
||||
name: row.name,
|
||||
value: row.value,
|
||||
};
|
||||
});
|
||||
initData(pieData);
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
77
src/views/business/components/businessThere.vue
Normal file
77
src/views/business/components/businessThere.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<custom-echart-line :chart-data="state.data" height="100%" :option="state.option" />
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue';
|
||||
import { isEmpty } from '@/utils';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
option: {
|
||||
color: ['#35D0C0'],
|
||||
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;
|
||||
},
|
||||
},
|
||||
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: [],
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (!isEmpty(val)) {
|
||||
state.data = val;
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
94
src/views/business/components/businessTwo.vue
Normal file
94
src/views/business/components/businessTwo.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<custom-echart-bar :chart-data="state.data" height="100%" :option="state.option" />
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue';
|
||||
import { isEmpty } from '@/utils';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
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: [],
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (!isEmpty(val)) {
|
||||
state.data = val;
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
@ -2,18 +2,24 @@
|
||||
<el-row class="data-home-index">
|
||||
<el-col :span="6" class="left-charts">
|
||||
<div class="left-charts-item">
|
||||
<customBack top-title=" " :top-postion="'left'">
|
||||
<template #back> </template>
|
||||
<customBack top-title="生产经营主体数量统计" :top-postion="'left'">
|
||||
<template #back>
|
||||
<businessOne :data="state.data.one" />
|
||||
</template>
|
||||
</customBack>
|
||||
</div>
|
||||
<div class="left-charts-item">
|
||||
<customBack top-title=" " :top-postion="'left'">
|
||||
<template #back> </template>
|
||||
<customBack top-title="生产经营主体数量" :top-postion="'left'">
|
||||
<template #back>
|
||||
<businessTwo :data="state.data.two" :query="state.queryCode" />
|
||||
</template>
|
||||
</customBack>
|
||||
</div>
|
||||
<div class="left-charts-item">
|
||||
<customBack top-title=" " :top-postion="'left'">
|
||||
<template #back> </template>
|
||||
<customBack top-title="近三年用地规模曲线" :top-postion="'left'">
|
||||
<template #back>
|
||||
<businessThere :data="state.data.there" />
|
||||
</template>
|
||||
</customBack>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -22,18 +28,24 @@
|
||||
</el-col>
|
||||
<el-col :span="6" class="right-charts">
|
||||
<div class="right-charts-item">
|
||||
<customBack top-title=" " :top-postion="'right'">
|
||||
<template #back> </template>
|
||||
<customBack top-title="证件状态看板" :top-postion="'right'">
|
||||
<template #back>
|
||||
<businessFour :data="state.data.four" />
|
||||
</template>
|
||||
</customBack>
|
||||
</div>
|
||||
<div class="right-charts-item">
|
||||
<customBack top-title=" " :top-postion="'right'">
|
||||
<template #back> </template>
|
||||
<customBack top-title="生产经营主体年收益排行" :top-postion="'right'">
|
||||
<template #back>
|
||||
<businessFive :data="state.data.five" />
|
||||
</template>
|
||||
</customBack>
|
||||
</div>
|
||||
<div class="right-charts-item">
|
||||
<customBack top-title=" " :top-postion="'right'">
|
||||
<template #back> </template>
|
||||
<customBack top-title="生产经营主体用地情况" :top-postion="'right'">
|
||||
<template #back>
|
||||
<businessSix :data="state.data.six" />
|
||||
</template>
|
||||
</customBack>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -42,10 +54,120 @@
|
||||
<script setup>
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import { useApp } from '@/hooks';
|
||||
import { sleep } from '@/utils';
|
||||
import businessMap from './components/businessMap.vue';
|
||||
import businessOne from './components/businessOne.vue';
|
||||
import businessTwo from './components/businessTwo.vue';
|
||||
import businessThere from './components/businessThere.vue';
|
||||
import businessFour from './components/businessFour.vue';
|
||||
import businessFive from './components/businessFive.vue';
|
||||
import businessSix from './components/businessSix.vue';
|
||||
|
||||
const app = useApp();
|
||||
const fiveRef = ref(null);
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
data: {},
|
||||
queryCode: '',
|
||||
});
|
||||
|
||||
// 加载
|
||||
const loadData = async () => {
|
||||
state.loading = true;
|
||||
// GetInputsInfo()
|
||||
// .then((res) => {
|
||||
// if (res.code === 200) {
|
||||
// state.data = res.data;
|
||||
// }
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// app.$message.error(err.msg);
|
||||
// });
|
||||
await sleep(500);
|
||||
state.data = {
|
||||
one: [
|
||||
{ value: 13.8, name: '农企/合作社' },
|
||||
{ value: 23.8, name: '农资企业' },
|
||||
{ value: 24.1, name: '种源企业' },
|
||||
{ value: 29.8, name: '生产加工企业' },
|
||||
{ value: 8.5, name: '农户' },
|
||||
],
|
||||
two: [
|
||||
{ name: '耿马镇', value: 870 },
|
||||
{ name: '勐撒镇', value: 603 },
|
||||
{ name: '勐永镇', value: 854 },
|
||||
{ name: '孟定镇', value: 635 },
|
||||
{ name: '勐简乡', value: 795 },
|
||||
{ name: '贺派乡', value: 662 },
|
||||
{ name: '四排山乡', value: 584 },
|
||||
{ name: '芒洪乡', value: 682 },
|
||||
{ name: '大兴乡', value: 664 },
|
||||
{ name: '信阳', value: 555 },
|
||||
{ name: '新乡', value: 532 },
|
||||
{ name: '大同', value: 511 },
|
||||
],
|
||||
there: [
|
||||
{ value: 66, name: '2021' },
|
||||
{ value: 100, name: '2022' },
|
||||
{ value: 50, name: '2023' },
|
||||
{ value: 150, name: '2024' },
|
||||
{ value: 80, name: '2025' },
|
||||
],
|
||||
four: [
|
||||
{ value: 58.9, label: '灌溉水田' },
|
||||
{ value: 56.1, label: '基地地' },
|
||||
{ value: 60.8, label: '望天田' },
|
||||
{ value: 60.6, label: '水浇地' },
|
||||
{ value: 32.6, label: '林地' },
|
||||
{ value: 25.8, label: '育苗地' },
|
||||
{ value: 56.0, label: '果园' },
|
||||
{ value: 52.4, label: '草地' },
|
||||
{ value: 6.3, label: '观测用地' },
|
||||
{ value: 6.1, label: '监测用地' },
|
||||
],
|
||||
five: [
|
||||
{ name: '耿马镇', value: 87.84 },
|
||||
{ name: '勐撒镇', value: 60.7 },
|
||||
{ name: '勐永镇', value: 85.84 },
|
||||
{ name: '孟定镇', value: 63.25 },
|
||||
{ name: '勐简乡', value: 79.45 },
|
||||
{ name: '贺派乡', value: 66.22 },
|
||||
{ name: '四排山乡', value: 58.34 },
|
||||
{ name: '芒洪乡', value: 68.12 },
|
||||
{ name: '大兴乡', value: 66.34 },
|
||||
{ name: '信阳', value: 55.75 },
|
||||
{ name: '新乡', value: 53.32 },
|
||||
{ name: '大同', value: 51.11 },
|
||||
],
|
||||
six: [
|
||||
{
|
||||
name: '农企/合作社',
|
||||
value: 25,
|
||||
},
|
||||
{
|
||||
name: '农资企业',
|
||||
value: 40,
|
||||
},
|
||||
{
|
||||
name: '种源企业',
|
||||
value: 24,
|
||||
},
|
||||
{
|
||||
name: '生产加工企业',
|
||||
value: 32,
|
||||
},
|
||||
{
|
||||
name: '农户',
|
||||
value: 32,
|
||||
},
|
||||
],
|
||||
};
|
||||
state.loading = false;
|
||||
};
|
||||
|
||||
loadData();
|
||||
|
||||
const handleCommand = (data) => {
|
||||
state.queryCode = data.value;
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.data-home-index {
|
||||
|
@ -26,6 +26,7 @@
|
||||
<el-col :span="12">
|
||||
<inputsMap></inputsMap>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="6" class="right-charts">
|
||||
<div class="right-charts-item">
|
||||
<customBack top-title="生产主体统计" :top-postion="'right'">
|
||||
|
Loading…
x
Reference in New Issue
Block a user