产出品管理 - 产出品概览页面饼图展示开发
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 }; | ||||||
|  | } | ||||||
| @ -104,12 +104,12 @@ | |||||||
|       .el-table__empty-text { |       .el-table__empty-text { | ||||||
|         width: 200px; |         width: 200px; | ||||||
|       } |       } | ||||||
|       .el-button-custom{ |       .el-button-custom { | ||||||
|         font-size: 14px !important; |         font-size: 14px !important; | ||||||
|         color: #25bf82; |         color: #25bf82; | ||||||
|         padding: 0; |         padding: 0; | ||||||
|       } |       } | ||||||
|       .el-button-delete{ |       .el-button-delete { | ||||||
|         font-size: 14px !important; |         font-size: 14px !important; | ||||||
|         color: #ff4d4f; |         color: #ff4d4f; | ||||||
|         padding: 0; |         padding: 0; | ||||||
| @ -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; | ||||||
| @ -356,7 +355,7 @@ | |||||||
|     font-weight: bold; |     font-weight: bold; | ||||||
|     margin-bottom: 20px; |     margin-bottom: 20px; | ||||||
|   } |   } | ||||||
|   .dialog-form-item{ |   .dialog-form-item { | ||||||
|     margin-right: 20px; |     margin-right: 20px; | ||||||
|     .el-input, |     .el-input, | ||||||
|     .el-select { |     .el-select { | ||||||
| @ -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