产出品管理 - 产出品概览页面饼图展示开发
This commit is contained in:
parent
f9f83986df
commit
b741c624f2
@ -10,6 +10,7 @@ declare module 'vue' {
|
|||||||
AreaCascader: typeof import('./src/components/AreaCascader/index.vue')['default']
|
AreaCascader: typeof import('./src/components/AreaCascader/index.vue')['default']
|
||||||
AreaSelect: typeof import('./src/components/AreaSelect/index.vue')['default']
|
AreaSelect: typeof import('./src/components/AreaSelect/index.vue')['default']
|
||||||
CodeDialog: typeof import('./src/components/code-dialog/index.vue')['default']
|
CodeDialog: typeof import('./src/components/code-dialog/index.vue')['default']
|
||||||
|
CustomEchartPie: typeof import('./src/components/custom-echart-pie/index.vue')['default']
|
||||||
FileUploader: typeof import('./src/components/FileUploader/index.vue')['default']
|
FileUploader: typeof import('./src/components/FileUploader/index.vue')['default']
|
||||||
LandSelect: typeof import('./src/components/LandSelect.vue')['default']
|
LandSelect: typeof import('./src/components/LandSelect.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="chartRef" :style="{ height, width }"></div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { ref, reactive, watch, watchEffect } from 'vue';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
import { useEcharts } from '../../hooks/useEcharts';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'CustomEchartPie',
|
||||||
|
props: {
|
||||||
|
chartData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
option: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '100%',
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: 'calc(100vh - 78px)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['click'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const chartRef = ref(null);
|
||||||
|
const { setOptions, getInstance, resize, startAutoPlay } = useEcharts(chartRef);
|
||||||
|
const option = reactive({
|
||||||
|
tooltip: {
|
||||||
|
backgroundColor: '#fff', // 背景颜色(支持RGBA格式)
|
||||||
|
borderColor: 'rgba(0, 0, 0, 0.1)', // 边框颜色
|
||||||
|
borderWidth: 1, // 边框宽度
|
||||||
|
textStyle: {
|
||||||
|
color: '#333', // 文字颜色
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
formatter: '{b} ({c})',
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
radius: '72%',
|
||||||
|
center: ['50%', '55%'],
|
||||||
|
data: [],
|
||||||
|
labelLine: { show: true },
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
formatter: '{b} \n ({d}%)',
|
||||||
|
color: '#B1B9D3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
props.chartData && initCharts();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.size,
|
||||||
|
() => {
|
||||||
|
resize();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function initCharts() {
|
||||||
|
if (props.option) {
|
||||||
|
Object.assign(option, cloneDeep(props.option));
|
||||||
|
}
|
||||||
|
option.series[0].data = props.chartData;
|
||||||
|
setOptions(option);
|
||||||
|
startAutoPlay({
|
||||||
|
interval: 2000,
|
||||||
|
seriesIndex: 0,
|
||||||
|
showTooltip: true,
|
||||||
|
});
|
||||||
|
resize();
|
||||||
|
getInstance()?.off('click', onClick);
|
||||||
|
getInstance()?.on('click', onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClick(params) {
|
||||||
|
emit('click', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { chartRef };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
84
sub-government-affairs-service/src/hooks/useBreakpoint.js
Normal file
84
sub-government-affairs-service/src/hooks/useBreakpoint.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { ref, computed, unref } from 'vue';
|
||||||
|
import { useEventListener } from './useEventListener';
|
||||||
|
|
||||||
|
let globalScreenRef = 0;
|
||||||
|
let globalWidthRef = 0;
|
||||||
|
let globalRealWidthRef = 0;
|
||||||
|
|
||||||
|
const screenMap = new Map();
|
||||||
|
screenMap.set('XS', 480);
|
||||||
|
screenMap.set('SM', 576);
|
||||||
|
screenMap.set('MD', 768);
|
||||||
|
screenMap.set('LG', 992);
|
||||||
|
screenMap.set('XL', 1200);
|
||||||
|
screenMap.set('XXL', 1600);
|
||||||
|
|
||||||
|
export function useBreakpoint() {
|
||||||
|
return {
|
||||||
|
screenRef: computed(() => unref(globalScreenRef)),
|
||||||
|
widthRef: globalWidthRef,
|
||||||
|
realWidthRef: globalRealWidthRef,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just call it once
|
||||||
|
export function createBreakpointListen(fn) {
|
||||||
|
const screenRef = ref('XL');
|
||||||
|
const realWidthRef = ref(window.innerWidth);
|
||||||
|
|
||||||
|
function getWindowWidth() {
|
||||||
|
const width = document.body.clientWidth;
|
||||||
|
const xs = screenMap.get('XS');
|
||||||
|
const sm = screenMap.get('SM');
|
||||||
|
const md = screenMap.get('MD');
|
||||||
|
const lg = screenMap.get('LG');
|
||||||
|
const xl = screenMap.get('XL');
|
||||||
|
const xxl = screenMap.set('XXL', 1600);
|
||||||
|
if (width < xs) {
|
||||||
|
screenRef.value = xs;
|
||||||
|
} else if (width < sm) {
|
||||||
|
screenRef.value = sm;
|
||||||
|
} else if (width < md) {
|
||||||
|
screenRef.value = md;
|
||||||
|
} else if (width < lg) {
|
||||||
|
screenRef.value = lg;
|
||||||
|
} else if (width < xl) {
|
||||||
|
screenRef.value = xl;
|
||||||
|
} else {
|
||||||
|
screenRef.value = xxl;
|
||||||
|
}
|
||||||
|
realWidthRef.value = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
useEventListener({
|
||||||
|
el: window,
|
||||||
|
name: 'resize',
|
||||||
|
|
||||||
|
listener: () => {
|
||||||
|
getWindowWidth();
|
||||||
|
resizeFn();
|
||||||
|
},
|
||||||
|
// wait: 100,
|
||||||
|
});
|
||||||
|
|
||||||
|
getWindowWidth();
|
||||||
|
globalScreenRef = computed(() => unref(screenRef));
|
||||||
|
globalWidthRef = computed(() => screenMap.get(unref(screenRef)));
|
||||||
|
globalRealWidthRef = computed(() => unref(realWidthRef));
|
||||||
|
|
||||||
|
function resizeFn() {
|
||||||
|
fn?.({
|
||||||
|
screen: globalScreenRef,
|
||||||
|
width: globalWidthRef,
|
||||||
|
realWidth: globalRealWidthRef,
|
||||||
|
screenMap,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeFn();
|
||||||
|
return {
|
||||||
|
screenRef: globalScreenRef,
|
||||||
|
widthRef: globalWidthRef,
|
||||||
|
realWidthRef: globalRealWidthRef,
|
||||||
|
};
|
||||||
|
}
|
191
sub-government-affairs-service/src/hooks/useEcharts.js
Normal file
191
sub-government-affairs-service/src/hooks/useEcharts.js
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import { unref, nextTick, watch, computed, ref } from 'vue';
|
||||||
|
import { useDebounceFn, tryOnUnmounted } from '@vueuse/core';
|
||||||
|
import { useTimeoutFn } from './useTimeout';
|
||||||
|
import { useEventListener } from './useEventListener';
|
||||||
|
import { useBreakpoint } from './useBreakpoint';
|
||||||
|
import echarts from '../utils/echarts';
|
||||||
|
|
||||||
|
export const useEcharts = (elRef, theme = 'default') => {
|
||||||
|
// 新增轮播相关状态
|
||||||
|
const autoPlayTimer = ref(null);
|
||||||
|
const currentIndex = ref(-1);
|
||||||
|
const dataLength = ref(0);
|
||||||
|
|
||||||
|
// 新增方法 - 启动轮播
|
||||||
|
const startAutoPlay = (options = {}) => {
|
||||||
|
const {
|
||||||
|
interval = 2000, // 轮播间隔(ms)
|
||||||
|
seriesIndex = 0, // 默认操作第一个系列
|
||||||
|
showTooltip = true, // 是否显示提示框
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
stopAutoPlay(); // 先停止已有轮播
|
||||||
|
|
||||||
|
// 获取数据长度
|
||||||
|
const seriesData = unref(getOptions).series?.[seriesIndex]?.data;
|
||||||
|
dataLength.value = seriesData?.length || 0;
|
||||||
|
if (dataLength.value === 0) return;
|
||||||
|
|
||||||
|
autoPlayTimer.value = setInterval(() => {
|
||||||
|
currentIndex.value = (currentIndex.value + 1) % dataLength.value;
|
||||||
|
|
||||||
|
// 执行轮播动作
|
||||||
|
chartInstance?.dispatchAction({
|
||||||
|
type: 'downplay',
|
||||||
|
seriesIndex: seriesIndex,
|
||||||
|
});
|
||||||
|
chartInstance?.dispatchAction({
|
||||||
|
type: 'highlight',
|
||||||
|
seriesIndex: seriesIndex,
|
||||||
|
dataIndex: currentIndex.value,
|
||||||
|
});
|
||||||
|
if (showTooltip) {
|
||||||
|
chartInstance?.dispatchAction({
|
||||||
|
type: 'showTip',
|
||||||
|
seriesIndex: seriesIndex,
|
||||||
|
dataIndex: currentIndex.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增方法 - 停止轮播
|
||||||
|
const stopAutoPlay = () => {
|
||||||
|
if (autoPlayTimer.value) {
|
||||||
|
clearInterval(autoPlayTimer.value);
|
||||||
|
autoPlayTimer.value = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDarkMode = computed(() => {
|
||||||
|
return theme === 'default' ? 'dark' : theme;
|
||||||
|
});
|
||||||
|
let chartInstance = null;
|
||||||
|
let resizeFn = resize;
|
||||||
|
const cacheOptions = ref({});
|
||||||
|
let removeResizeFn = null;
|
||||||
|
|
||||||
|
resizeFn = useDebounceFn(resize, 200);
|
||||||
|
|
||||||
|
const getOptions = computed(() => {
|
||||||
|
if (getDarkMode.value !== 'dark') {
|
||||||
|
return cacheOptions.value;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
...cacheOptions.value,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function initCharts(t = theme) {
|
||||||
|
const el = unref(elRef);
|
||||||
|
if (!el || !unref(el)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
if (el.offsetWidth === 0 || el.offsetHeight === 0) {
|
||||||
|
// console.warn('图表容器不可见,延迟初始化');
|
||||||
|
useTimeoutFn(() => initCharts(t), 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chartInstance = echarts.init(el, t);
|
||||||
|
const { removeEvent } = useEventListener({
|
||||||
|
el: window,
|
||||||
|
name: 'resize',
|
||||||
|
listener: resizeFn,
|
||||||
|
});
|
||||||
|
removeResizeFn = removeEvent;
|
||||||
|
const { widthRef } = useBreakpoint();
|
||||||
|
if (unref(widthRef) <= 768 || el.offsetHeight === 0) {
|
||||||
|
useTimeoutFn(() => {
|
||||||
|
resizeFn();
|
||||||
|
}, 30);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOptions(options = {}, clear = true) {
|
||||||
|
const mergedOptions = {
|
||||||
|
animation: true,
|
||||||
|
animationDuration: 3000,
|
||||||
|
animationEasing: 'cubicOut',
|
||||||
|
...unref(options),
|
||||||
|
animationThreshold: 2000, // 数据量超过2000自动关闭动画
|
||||||
|
animationDelayUpdate: (idx) => idx * 50, // 数据项延迟
|
||||||
|
};
|
||||||
|
cacheOptions.value = mergedOptions;
|
||||||
|
cacheOptions.value = options;
|
||||||
|
if (unref(elRef)?.offsetHeight === 0) {
|
||||||
|
useTimeoutFn(() => {
|
||||||
|
setOptions(unref(getOptions));
|
||||||
|
}, 30);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
useTimeoutFn(() => {
|
||||||
|
if (!chartInstance) {
|
||||||
|
initCharts(getDarkMode.value ?? 'default');
|
||||||
|
|
||||||
|
if (!chartInstance) return;
|
||||||
|
}
|
||||||
|
clear && chartInstance?.clear();
|
||||||
|
|
||||||
|
chartInstance?.setOption(unref(getOptions));
|
||||||
|
}, 30);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
chartInstance?.resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册地图数据
|
||||||
|
* @param {string} mapName - 地图名称
|
||||||
|
* @param {object} geoJSON - GeoJSON 数据
|
||||||
|
*/
|
||||||
|
function registerMap(mapName, geoJSON) {
|
||||||
|
if (!mapName || !geoJSON) {
|
||||||
|
console.warn('地图名称或 GeoJSON 数据无效');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
echarts.registerMap(mapName, geoJSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => getDarkMode.value,
|
||||||
|
(theme) => {
|
||||||
|
if (chartInstance) {
|
||||||
|
chartInstance.dispose();
|
||||||
|
initCharts(theme);
|
||||||
|
setOptions(cacheOptions.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
tryOnUnmounted(() => {
|
||||||
|
stopAutoPlay(); // 清理定时器
|
||||||
|
if (!chartInstance) return;
|
||||||
|
removeResizeFn();
|
||||||
|
chartInstance.dispose();
|
||||||
|
chartInstance = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
function getInstance() {
|
||||||
|
if (!chartInstance) {
|
||||||
|
initCharts(getDarkMode.value ?? 'default');
|
||||||
|
}
|
||||||
|
return chartInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
setOptions,
|
||||||
|
resize,
|
||||||
|
echarts,
|
||||||
|
getInstance: () => chartInstance,
|
||||||
|
registerMap,
|
||||||
|
startAutoPlay, // 暴露轮播方法
|
||||||
|
stopAutoPlay,
|
||||||
|
};
|
||||||
|
};
|
38
sub-government-affairs-service/src/hooks/useEventListener.js
Normal file
38
sub-government-affairs-service/src/hooks/useEventListener.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { ref, watch, unref } from 'vue';
|
||||||
|
import { useThrottleFn, useDebounceFn } from '@vueuse/core';
|
||||||
|
|
||||||
|
export function useEventListener({ el = window, name, listener, options, autoRemove = true, isDebounce = true, wait = 80 }) {
|
||||||
|
let remove;
|
||||||
|
const isAddRef = ref(false);
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
const element = ref(el);
|
||||||
|
|
||||||
|
const handler = isDebounce ? useDebounceFn(listener, wait) : useThrottleFn(listener, wait);
|
||||||
|
const realHandler = wait ? handler : listener;
|
||||||
|
const removeEventListener = (e) => {
|
||||||
|
isAddRef.value = true;
|
||||||
|
e.removeEventListener(name, realHandler, options);
|
||||||
|
};
|
||||||
|
const addEventListener = (e) => e.addEventListener(name, realHandler, options);
|
||||||
|
|
||||||
|
const removeWatch = watch(
|
||||||
|
element,
|
||||||
|
(v, _ov, cleanUp) => {
|
||||||
|
if (v) {
|
||||||
|
!unref(isAddRef) && addEventListener(v);
|
||||||
|
cleanUp(() => {
|
||||||
|
autoRemove && removeEventListener(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
remove = () => {
|
||||||
|
removeEventListener(element.value);
|
||||||
|
removeWatch();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { removeEvent: remove };
|
||||||
|
}
|
44
sub-government-affairs-service/src/hooks/useTimeout.js
Normal file
44
sub-government-affairs-service/src/hooks/useTimeout.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { tryOnUnmounted } from '@vueuse/core';
|
||||||
|
|
||||||
|
export function useTimeoutFn(handle, wait, native = false) {
|
||||||
|
if (typeof handle !== 'function') {
|
||||||
|
throw new Error('handle is not Function!');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { readyRef, stop, start } = useTimeoutRef(wait);
|
||||||
|
if (native) {
|
||||||
|
handle();
|
||||||
|
} else {
|
||||||
|
watch(
|
||||||
|
readyRef,
|
||||||
|
(maturity) => {
|
||||||
|
maturity && handle();
|
||||||
|
},
|
||||||
|
{ immediate: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return { readyRef, stop, start };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTimeoutRef(wait) {
|
||||||
|
const readyRef = ref(false);
|
||||||
|
|
||||||
|
let timer;
|
||||||
|
function stop() {
|
||||||
|
readyRef.value = false;
|
||||||
|
timer && window.clearTimeout(timer);
|
||||||
|
}
|
||||||
|
function start() {
|
||||||
|
stop();
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
readyRef.value = true;
|
||||||
|
}, wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
start();
|
||||||
|
|
||||||
|
tryOnUnmounted(stop);
|
||||||
|
|
||||||
|
return { readyRef, stop, start };
|
||||||
|
}
|
@ -247,7 +247,6 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 3px 0;
|
padding: 3px 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
.el-icon-custom {
|
.el-icon-custom {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
@ -373,3 +372,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.statistics-cont {
|
||||||
|
padding: 10px 20px;
|
||||||
|
.statistics-echart-box {
|
||||||
|
height: 400px;
|
||||||
|
padding-bottom: 50px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.statistics-echart-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
66
sub-government-affairs-service/src/utils/echarts.js
Normal file
66
sub-government-affairs-service/src/utils/echarts.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import * as echarts from 'echarts/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BarChart,
|
||||||
|
LineChart,
|
||||||
|
PieChart,
|
||||||
|
MapChart,
|
||||||
|
PictorialBarChart,
|
||||||
|
RadarChart,
|
||||||
|
GraphChart,
|
||||||
|
GaugeChart,
|
||||||
|
ScatterChart,
|
||||||
|
EffectScatterChart,
|
||||||
|
} from 'echarts/charts';
|
||||||
|
import 'echarts-gl';
|
||||||
|
import 'echarts-liquidfill';
|
||||||
|
import 'echarts-wordcloud';
|
||||||
|
|
||||||
|
import {
|
||||||
|
TitleComponent,
|
||||||
|
TooltipComponent,
|
||||||
|
GridComponent,
|
||||||
|
PolarComponent,
|
||||||
|
AriaComponent,
|
||||||
|
ParallelComponent,
|
||||||
|
LegendComponent,
|
||||||
|
RadarComponent,
|
||||||
|
ToolboxComponent,
|
||||||
|
DataZoomComponent,
|
||||||
|
VisualMapComponent,
|
||||||
|
TimelineComponent,
|
||||||
|
CalendarComponent,
|
||||||
|
GraphicComponent,
|
||||||
|
} from 'echarts/components';
|
||||||
|
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers';
|
||||||
|
|
||||||
|
echarts.use([
|
||||||
|
LegendComponent,
|
||||||
|
TitleComponent,
|
||||||
|
TooltipComponent,
|
||||||
|
GridComponent,
|
||||||
|
PolarComponent,
|
||||||
|
AriaComponent,
|
||||||
|
ParallelComponent,
|
||||||
|
BarChart,
|
||||||
|
LineChart,
|
||||||
|
PieChart,
|
||||||
|
MapChart,
|
||||||
|
RadarChart,
|
||||||
|
CanvasRenderer,
|
||||||
|
PictorialBarChart,
|
||||||
|
RadarComponent,
|
||||||
|
ToolboxComponent,
|
||||||
|
DataZoomComponent,
|
||||||
|
VisualMapComponent,
|
||||||
|
TimelineComponent,
|
||||||
|
CalendarComponent,
|
||||||
|
GraphicComponent,
|
||||||
|
GraphChart,
|
||||||
|
GaugeChart,
|
||||||
|
ScatterChart,
|
||||||
|
EffectScatterChart,
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default echarts;
|
@ -14,3 +14,67 @@ import { getAssetsFile } from '@/utils';
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- <template>
|
||||||
|
<div class="app-container">
|
||||||
|
<div class="container-custom">
|
||||||
|
<h2 class="custom-h2">产出品概览</h2>
|
||||||
|
<div ref="searchBarRef" class="search-box">
|
||||||
|
<div class="search-bar">
|
||||||
|
<div class="search-bar-left">
|
||||||
|
<el-form ref="searchForm" :inline="true" :model="formInline" class="demo-form-inline" :label-width="'auto'">
|
||||||
|
<el-form-item label="" style="margin-left: -15px">
|
||||||
|
<AreaCascader v-model:region-code="formInline.regionCode" v-model:grid-id="formInline.gridId" label="行政区域-网格" :width="500" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="">
|
||||||
|
<el-button type="primary" icon="Search" @click="onSubmit">查询</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="statistics-cont">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="12" class="statistics-echart-box">
|
||||||
|
<p class="statistics-echart-title">产出品产量数据</p>
|
||||||
|
<customEchartPie ref="pie1" :chart-data="chartData1" :option="option" :width="'100%'" :height="'100%'"></customEchartPie>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, computed, onMounted } from 'vue';
|
||||||
|
import customEchartPie from '@/components/custom-echart-pie';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
// 查询条件
|
||||||
|
const formInline = reactive({
|
||||||
|
regionCode: '',
|
||||||
|
regionName: '',
|
||||||
|
gridId: '',
|
||||||
|
gridName: '',
|
||||||
|
});
|
||||||
|
const searchForm = ref(null);
|
||||||
|
|
||||||
|
const chartData1 = ref([
|
||||||
|
{ value: 1048, name: '蔬菜类' },
|
||||||
|
{ value: 735, name: '水果类' },
|
||||||
|
{ value: 484, name: '药材类' },
|
||||||
|
]);
|
||||||
|
const option = reactive({
|
||||||
|
tooltip: {
|
||||||
|
formatter: '{b} ({c} 吨)',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const onSubmit = () => {
|
||||||
|
console.log(formInline);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// onSubmit();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style> -->
|
||||||
|
@ -137,7 +137,7 @@
|
|||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-descriptions title="区块链认证信息" border class="mb-20 custom-descriptions" :column="1">
|
<el-descriptions title="区块链认证信息" border class="mb-20 custom-descriptions" :column="1">
|
||||||
<el-descriptions-item label="质检报告">
|
<el-descriptions-item label="认证信息">
|
||||||
<img :src="dialogForm?.traceUrl ?? ''" alt="" />
|
<img :src="dialogForm?.traceUrl ?? ''" alt="" />
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
@ -274,7 +274,7 @@ const seedTypeChange = () => {
|
|||||||
// 重新获取表格数据,需添加参数
|
// 重新获取表格数据,需添加参数
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabsRadio = ref(2);
|
const tabsRadio = ref(1);
|
||||||
const dialogFormVisible = ref(false);
|
const dialogFormVisible = ref(false);
|
||||||
const dialogRef = ref(null);
|
const dialogRef = ref(null);
|
||||||
const dialogTitle = ref('溯源产品详情');
|
const dialogTitle = ref('溯源产品详情');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user