Merge branch 'dev' of http://192.168.18.88:8077/sznyb/daimp-front into dev
| @ -25,6 +25,7 @@ | ||||
|     "echarts": "^5.6.0", | ||||
|     "echarts-gl": "^2.0.9", | ||||
|     "echarts-liquidfill": "^3.1.0", | ||||
|     "echarts-wordcloud": "^2.1.0", | ||||
|     "element-plus": "^2.7.3", | ||||
|     "file-saver": "^2.0.5", | ||||
|     "js-base64": "^3.7.7", | ||||
|  | ||||
| @ -103,7 +103,6 @@ export default { | ||||
|       if (props.option) { | ||||
|         Object.assign(option, cloneDeep(props.option)); | ||||
|       } | ||||
|       option.series[0].data = props.chartData; | ||||
|       setOptions(option); | ||||
|       resize(); | ||||
|       getInstance()?.off('click', onClick); | ||||
|  | ||||
							
								
								
									
										73
									
								
								main/src/components/custom-echart-pie-gauge/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,73 @@ | ||||
| <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: 'CustomEchartPieGauge', | ||||
|   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 } = useEcharts(chartRef); | ||||
|     const option = reactive({ | ||||
|       series: [], | ||||
|     }); | ||||
| 
 | ||||
|     watchEffect(() => { | ||||
|       props.chartData && initCharts(); | ||||
|     }); | ||||
| 
 | ||||
|     watch( | ||||
|       () => props.size, | ||||
|       () => { | ||||
|         resize(); | ||||
|       }, | ||||
|       { | ||||
|         immediate: true, | ||||
|       } | ||||
|     ); | ||||
| 
 | ||||
|     function initCharts() { | ||||
|       if (props.option) { | ||||
|         Object.assign(option, cloneDeep(props.option)); | ||||
|       } | ||||
|       option.series = props.chartData; | ||||
|       setOptions(option); | ||||
|       resize(); | ||||
|       getInstance()?.off('click', onClick); | ||||
|       getInstance()?.on('click', onClick); | ||||
|     } | ||||
| 
 | ||||
|     function onClick(params) { | ||||
|       emit('click', params); | ||||
|     } | ||||
| 
 | ||||
|     return { chartRef }; | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										73
									
								
								main/src/components/custom-echart-word-cloud/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,73 @@ | ||||
| <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: 'CustomEchartWordCloud', | ||||
|   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 } = useEcharts(chartRef); | ||||
|     const option = reactive({ | ||||
|       series: [], | ||||
|     }); | ||||
| 
 | ||||
|     watchEffect(() => { | ||||
|       props.chartData && initCharts(); | ||||
|     }); | ||||
| 
 | ||||
|     watch( | ||||
|       () => props.size, | ||||
|       () => { | ||||
|         resize(); | ||||
|       }, | ||||
|       { | ||||
|         immediate: true, | ||||
|       } | ||||
|     ); | ||||
| 
 | ||||
|     function initCharts() { | ||||
|       if (props.option) { | ||||
|         Object.assign(option, cloneDeep(props.option)); | ||||
|       } | ||||
|       option.series = props.chartData; | ||||
|       setOptions(option); | ||||
|       resize(); | ||||
|       getInstance()?.off('click', onClick); | ||||
|       getInstance()?.on('click', onClick); | ||||
|     } | ||||
| 
 | ||||
|     function onClick(params) { | ||||
|       emit('click', params); | ||||
|     } | ||||
| 
 | ||||
|     return { chartRef }; | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
| @ -40,7 +40,7 @@ const formatterIcon = (row) => { | ||||
|   &__more { | ||||
|     padding: 20px 5px; | ||||
|     font-size: 20px; | ||||
|     color: $color-primary; | ||||
|     color: var(--el-color-primary); | ||||
|     cursor: pointer; | ||||
|   } | ||||
|   .el-button { | ||||
|  | ||||
| @ -27,7 +27,7 @@ import { reactive, ref, watch } from 'vue'; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   title: { type: String, default: '' }, | ||||
|   shadow: { type: Boolean, default: true }, | ||||
|   shadow: { type: Boolean, default: false }, | ||||
|   filter: { type: Boolean, default: false }, | ||||
|   data: { type: Array, default: () => [] }, | ||||
|   option: { | ||||
|  | ||||
| @ -15,6 +15,8 @@ import CustomEchartLineLine from './custom-echart-line-line'; | ||||
| import CustomEchartBubble from './custom-echart-bubble'; | ||||
| import CustomEchartPie3d from './custom-echart-pie-3d'; | ||||
| import CustomEchartWaterDroplet from './custom-echart-water-droplet'; | ||||
| import CustomEchartPieGauge from './custom-echart-pie-gauge'; | ||||
| import CustomEchartWordCloud from './custom-echart-word-cloud'; | ||||
| 
 | ||||
| export { | ||||
|   SvgIcon, | ||||
| @ -34,4 +36,6 @@ export { | ||||
|   CustomEchartBubble, | ||||
|   CustomEchartPie3d, | ||||
|   CustomEchartWaterDroplet, | ||||
|   CustomEchartPieGauge, | ||||
|   CustomEchartWordCloud, | ||||
| }; | ||||
|  | ||||
| @ -1,8 +1,9 @@ | ||||
| import * as echarts from 'echarts/core'; | ||||
| 
 | ||||
| import { BarChart, LineChart, PieChart, MapChart, PictorialBarChart, RadarChart, GraphChart } from 'echarts/charts'; | ||||
| import { BarChart, LineChart, PieChart, MapChart, PictorialBarChart, RadarChart, GraphChart, GaugeChart } from 'echarts/charts'; | ||||
| import 'echarts-gl'; | ||||
| import 'echarts-liquidfill'; | ||||
| import 'echarts-wordcloud'; | ||||
| 
 | ||||
| import { | ||||
|   TitleComponent, | ||||
| @ -46,6 +47,7 @@ echarts.use([ | ||||
|   CalendarComponent, | ||||
|   GraphicComponent, | ||||
|   GraphChart, | ||||
|   GaugeChart, | ||||
| ]); | ||||
| 
 | ||||
| export default echarts; | ||||
|  | ||||
| @ -2195,6 +2195,11 @@ echarts-liquidfill@^3.1.0: | ||||
|   resolved "https://registry.npmmirror.com/echarts-liquidfill/-/echarts-liquidfill-3.1.0.tgz#4ec70f3697382d0404c95fff9f3e8dd85c8377da" | ||||
|   integrity sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw== | ||||
| 
 | ||||
| echarts-wordcloud@^2.1.0: | ||||
|   version "2.1.0" | ||||
|   resolved "https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.1.0.tgz#c3de6fe267044f6c3343e4ff0e05eedb01c05096" | ||||
|   integrity sha512-Kt1JmbcROgb+3IMI48KZECK2AP5lG6bSsOEs+AsuwaWJxQom31RTNd6NFYI01E/YaI1PFZeueaupjlmzSQasjQ== | ||||
| 
 | ||||
| echarts@^5.6.0: | ||||
|   version "5.6.0" | ||||
|   resolved "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6" | ||||
|  | ||||
| @ -30,6 +30,7 @@ | ||||
|     "pinia": "^2.1.7", | ||||
|     "pinia-plugin-persistedstate": "^3.2.1", | ||||
|     "screenfull": "^6.0.2", | ||||
|     "splitpanes": "^4.0.3", | ||||
|     "vue": "^3.3.11", | ||||
|     "vue-router": "^4.2.5" | ||||
|   }, | ||||
|  | ||||
| @ -19,10 +19,12 @@ import { registerDirective } from './directives'; | ||||
| import { registerGlobalComponents } from './plugins/globalComponents'; | ||||
| import { registerElIcons } from './plugins/icon'; | ||||
| import { registerMicroApps } from './plugins/micro'; | ||||
| import { registerSplitpanes } from './plugins/splitpanes'; | ||||
| 
 | ||||
| const app = createApp(App); | ||||
| app.use(pinia).use(router).use(ElementPlus).use(Avue); | ||||
| registerGlobalComponents(app); | ||||
| registerElIcons(app); | ||||
| registerSplitpanes(app); | ||||
| registerDirective(app); | ||||
| registerMicroApps(app); | ||||
|  | ||||
							
								
								
									
										7
									
								
								sub-government-affairs-service/src/plugins/splitpanes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,7 @@ | ||||
| import { Splitpanes, Pane } from 'splitpanes'; | ||||
| import 'splitpanes/dist/splitpanes.css'; | ||||
| 
 | ||||
| export const registerSplitpanes = (app) => { | ||||
|   app.component('Splitpanes', Splitpanes); | ||||
|   app.component('Pane', Pane); | ||||
| }; | ||||
| @ -9,12 +9,6 @@ export default [ | ||||
|     redirect: '/sub-government-affairs-service/trace-home', | ||||
|     meta: { title: '溯源管理', icon: 'Document' }, | ||||
|     children: [ | ||||
|       { | ||||
|         path: '/sub-government-affairs-service/trace-index', | ||||
|         name: 'trace-index', | ||||
|         component: () => import('@/views/trace/statistic/index.vue'), | ||||
|         meta: { title: '溯源首页', icon: 'Document' }, | ||||
|       }, | ||||
|       { | ||||
|         path: '/sub-government-affairs-service/record', | ||||
|         name: 'record', | ||||
| @ -78,6 +72,12 @@ export default [ | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         path: '/sub-government-affairs-service/trace-statistic', | ||||
|         name: 'trace-statistic', | ||||
|         component: () => import('@/views/trace/statistic/index.vue'), | ||||
|         meta: { title: '溯源统计', icon: 'Document' }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
| @ -15,3 +15,7 @@ | ||||
|   height: auto; | ||||
|   max-height: calc(100vh - 130px); | ||||
| } | ||||
| 
 | ||||
| .splitpanes.default-theme .splitpanes__pane { | ||||
|   background-color: #fff !important; | ||||
| } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|  * @Author: zenghua.wang | ||||
|  * @Date: 2022-02-23 21:12:37 | ||||
|  * @LastEditors: zenghua.wang | ||||
|  * @LastEditTime: 2025-02-11 17:18:36 | ||||
|  * @LastEditTime: 2025-03-24 10:05:36 | ||||
|  */ | ||||
| import lodash from 'lodash'; | ||||
| import dayjs from 'dayjs'; | ||||
| @ -123,6 +123,26 @@ export const setDicLabel = (dicData, value) => { | ||||
|   } | ||||
|   return label; | ||||
| }; | ||||
| /** | ||||
|  * @Title 将tree数据结构打平 | ||||
|  * @param {*} tree | ||||
|  * @returns | ||||
|  */ | ||||
| export const flattenTree = (tree) => { | ||||
|   const result = []; | ||||
|   function traverse(node) { | ||||
|     result.push(node); | ||||
|     if (node.children && node.children.length > 0) { | ||||
|       node.children.forEach((child) => traverse(child)); | ||||
|     } | ||||
|   } | ||||
|   if (Array.isArray(tree)) { | ||||
|     tree.forEach((item) => traverse(item)); | ||||
|   } else { | ||||
|     traverse(tree); | ||||
|   } | ||||
|   return result; | ||||
| }; | ||||
| /** | ||||
|  * @Title 数组交集 | ||||
|  * @param {*} arr1 | ||||
|  | ||||
| @ -0,0 +1,421 @@ | ||||
| <template> | ||||
|   <CustomCard> | ||||
|     <div> | ||||
|       <el-row :gutter="20"> | ||||
|         <el-col :span="4"> | ||||
|           <el-tree | ||||
|             style="max-width: 600px" | ||||
|             :data="treeData" | ||||
|             node-key="id" | ||||
|             :default-expanded-keys="[selectTreeNode.id]" | ||||
|             :props="{ value: 'id' }" | ||||
|             :expand-on-click-node="false" | ||||
|             @node-click="handleNodeClick" | ||||
|           > | ||||
|             <template #default="{ data }"> | ||||
|               <div class="tree_node_" :class="{ nodeActive: data.id == selectTreeNode.id || data.id == selectTreeNode.pId }"> | ||||
|                 {{ data.label }} | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-tree> | ||||
|         </el-col> | ||||
|         <el-col :span="20"> | ||||
|           <avue-crud | ||||
|             ref="crudRef" | ||||
|             v-model="state.form" | ||||
|             v-model:search="state.query" | ||||
|             v-model:page="state.pageData" | ||||
|             :table-loading="state.loading" | ||||
|             :data="state.data" | ||||
|             :option="state.options" | ||||
|             @refresh-change="refreshChange" | ||||
|             @search-reset="searchChange" | ||||
|             @search-change="searchChange" | ||||
|             @selection-change="selectionChange" | ||||
|             @current-change="currentChange" | ||||
|             @size-change="sizeChange" | ||||
|             @row-del="rowDel" | ||||
|             @row-save="rowSave" | ||||
|             @row-update="rowUpdate" | ||||
|           > | ||||
|             <template #menu-left> | ||||
|               <el-button type="primary" icon="Plus" @click="onAdd">新增</el-button> | ||||
|               <el-button type="success" icon="download" @click="onExport">导出</el-button> | ||||
|             </template> | ||||
| 
 | ||||
|             <template #menu="scope"> | ||||
|               <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|             </template> | ||||
|           </avue-crud> | ||||
|         </el-col> | ||||
|       </el-row> | ||||
|     </div> | ||||
|   </CustomCard> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, nextTick } from 'vue'; | ||||
| import { useApp } from '@/hooks'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| import CustomCard from '@/components/CustomCard.vue'; | ||||
| import { getLandTypeTree, landTypeSave, getLandType, exportLandType, delLandType, editLandType } from '@/apis/baseInfo'; | ||||
| import { ElMessage } from 'element-plus'; | ||||
| 
 | ||||
| const { VITE_APP_BASE_API } = import.meta.env; | ||||
| const app = useApp(); | ||||
| 
 | ||||
| const selectTreeNode = ref({ | ||||
|   id: '', | ||||
|   label: '', | ||||
|   pId: '', | ||||
|   pName: '', | ||||
|   level: 0, | ||||
| }); | ||||
| const landTypesDic = ref([]); | ||||
| const crudRef = ref(null); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: { | ||||
|     current: 1, | ||||
|     size: 10, | ||||
|   }, | ||||
|   form: {}, | ||||
|   selection: [], | ||||
|   options: { | ||||
|     ...CRUD_OPTIONS, | ||||
|     addBtnText: '', | ||||
|     addBtn: false, | ||||
|     dialogWidth: 680, | ||||
|     selection: false, | ||||
|     refreshBtn: false, | ||||
|     column: [ | ||||
|       { label: '编号', prop: 'id', addDisplay: false, editDisplay: false }, | ||||
|       { | ||||
|         label: '用地分类', | ||||
|         prop: 'landType', | ||||
|         dicData: landTypesDic, | ||||
|         // type: 'select', | ||||
|         multiple: true, | ||||
|         span: 23, | ||||
|         props: { | ||||
|           value: 'id', | ||||
|           label: 'childLandCategory', | ||||
|         }, | ||||
|         rules: [ | ||||
|           { | ||||
|             required: true, | ||||
|             message: '请输入', | ||||
|             trigger: 'blur', | ||||
|           }, | ||||
|         ], | ||||
|         render: ({ row }) => { | ||||
|           return row.landType; | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '土地类别', | ||||
|         prop: 'landCategory', | ||||
|         addDisplay: false, | ||||
|         rules: [ | ||||
|           { | ||||
|             required: true, | ||||
|             message: '请输入', | ||||
|             trigger: 'blur', | ||||
|           }, | ||||
|         ], | ||||
|         render: ({ row }) => { | ||||
|           return row.landCategory; | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '状态', | ||||
|         prop: 'status', | ||||
|         render: ({ row }) => { | ||||
|           return row.status == '1' ? '启用' : '禁用'; | ||||
|         }, | ||||
|         addDisplay: false, | ||||
|         editDisplay: false, | ||||
|       }, | ||||
|     ], | ||||
|     actions: [ | ||||
|       { | ||||
|         name: ({ row }) => `${row.status == '0' ? '启' : '禁'}用`, | ||||
|         icon: 'edit', | ||||
|         event: ({ row }) => rowStatus(row), | ||||
|       }, | ||||
|       { | ||||
|         name: '编辑', | ||||
|         icon: 'edit', | ||||
|         event: ({ row }) => rowEdit(row), | ||||
|       }, | ||||
|       { | ||||
|         type: 'danger', | ||||
|         name: '删除', | ||||
|         icon: 'delete', | ||||
|         event: ({ row }) => rowDel(row), | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   pageData: { | ||||
|     total: 0, | ||||
|     currentPage: 1, | ||||
|     pageSize: 10, | ||||
|   }, | ||||
|   data: [], | ||||
|   currentRow: {}, | ||||
| }); | ||||
| 
 | ||||
| const treeData = ref([]); | ||||
| 
 | ||||
| const loadData = () => { | ||||
|   state.loading = true; | ||||
|   getLandType({ | ||||
|     pid: selectTreeNode.value.id, | ||||
|     ...state.query, | ||||
|   }) | ||||
|     .then((res) => { | ||||
|       if (res.code === 200) { | ||||
|         const { current, size, total, records } = res.data; | ||||
|         state.data = records; | ||||
|         state.pageData = { | ||||
|           currentPage: current || 1, | ||||
|           pageSize: size || 10, | ||||
|           total: total, | ||||
|         }; | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error(err.msg); | ||||
|       state.data = []; | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       state.loading = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   getLandTree(); | ||||
| }); | ||||
| 
 | ||||
| async function getLandTree() { | ||||
|   let res = await getLandTypeTree(); | ||||
|   if (res.code == 200) { | ||||
|     treeData.value = newTree(res.data, 0); | ||||
|     landTypesDic.value = res.data.map((v) => { | ||||
|       return { | ||||
|         id: v.id, | ||||
|         label: v.prentLandType, | ||||
|       }; | ||||
|     }); | ||||
|     console.log('treeData', treeData.value); | ||||
|   } | ||||
| } | ||||
| function newTree(arr, i) { | ||||
|   arr.forEach((v) => { | ||||
|     if (i == 0) { | ||||
|       v.label = v.prentLandType; | ||||
|     } else { | ||||
|       v.label = v.childLandCategory; | ||||
|     } | ||||
|     if (v.children) v.children = newTree(v.children, i + 1); | ||||
|   }); | ||||
|   return arr; | ||||
| } | ||||
| // 页数 | ||||
| const currentChange = (current) => { | ||||
|   state.query.current = current; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 条数 | ||||
| const sizeChange = (size) => { | ||||
|   state.query.current = 1; | ||||
|   state.query.size = size; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 搜索 | ||||
| const searchChange = (params, done) => { | ||||
|   if (done) done(); | ||||
|   state.query = params; | ||||
|   state.query.current = 1; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 刷新 | ||||
| const refreshChange = () => { | ||||
|   loadData(); | ||||
|   app.$message.success('刷新成功'); | ||||
| }; | ||||
| 
 | ||||
| // 选择 | ||||
| const selectionChange = (rows) => { | ||||
|   state.selection = rows; | ||||
| }; | ||||
| 
 | ||||
| const handleNodeClick = (data, node) => { | ||||
|   const { id } = data; | ||||
|   if (selectTreeNode.value.id != id) { | ||||
|     if (node.level < 2) { | ||||
|       selectTreeNode.value = handleNodeData({ data, level: node.level }); | ||||
|     } else selectTreeNode.value = handleNodeData({ data: node.parent.data, level: node.level }); | ||||
|     loadData(); | ||||
|   } else { | ||||
|     selectTreeNode.value = { id: '', label: '', level: 0 }; | ||||
|     state.data = []; | ||||
|   } | ||||
|   if (selectTreeNode.value.level < 1) { | ||||
|     state.options.dialogWidth = 680; | ||||
|     state.options.column[1].span = 23; | ||||
|     state.options.column[2].addDisplay = false; | ||||
|     delete state.options.column[1].addDisabled; | ||||
|     delete state.options.column[1].value; | ||||
|   } else { | ||||
|     state.options.column[2].addDisplay = true; | ||||
|     state.options.column[1].addDisabled = true; | ||||
|     state.options.column[1].value = selectTreeNode.value.label; | ||||
|     delete state.options.dialogWidth; | ||||
|     delete state.options.column[1].type; | ||||
|     delete state.options.column[1].span; | ||||
|   } | ||||
| }; | ||||
| function handleNodeData({ data, level }) { | ||||
|   return { | ||||
|     id: data.id, | ||||
|     label: data.label, | ||||
|     level, | ||||
|   }; | ||||
| } | ||||
| // 编辑状态 | ||||
| async function rowStatus(row) { | ||||
|   console.info('操作状态', row.$index); | ||||
|   const { id } = row; | ||||
|   let status = row.status == '1' ? '0' : '1'; | ||||
|   let params = { | ||||
|     id, | ||||
|     status, | ||||
|   }; | ||||
|   let res = await editLandType(params); | ||||
|   if (res.code == 200) { | ||||
|     ElMessage.success('操作成功'); | ||||
|     nextTick(() => { | ||||
|       state.data[row.$index].status = status; | ||||
|       loadData(); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| async function rowDel(row, done, loading) { | ||||
|   let res = await delLandType(row.id); | ||||
|   if (res.code === 200) { | ||||
|     app.$message.success('已删除!'); | ||||
|     loadData(); | ||||
|     done(); | ||||
|   } | ||||
|   loading(); | ||||
| } | ||||
| 
 | ||||
| const rowEdit = (row) => { | ||||
|   crudRef.value && crudRef.value.rowEdit(row); | ||||
| }; | ||||
| 
 | ||||
| const onAdd = () => { | ||||
|   crudRef.value && crudRef.value.rowAdd(); | ||||
| }; | ||||
| async function onExport() { | ||||
|   console.log('test ---'); | ||||
|   if (selectTreeNode.value.level < 1) return ElMessage.warning('请选择用地分类'); | ||||
|   let res = await exportLandType({ | ||||
|     pid: selectTreeNode.value.id, | ||||
|   }); | ||||
|   console.log('edxport', res); | ||||
|   if (res.status == 200) { | ||||
|     let a = document.createElement('a'); | ||||
|     let blob = new Blob([res.data]); | ||||
|     let link = window.URL.createObjectURL(blob); | ||||
|     a.href = link; | ||||
|     a.download = '用地分类.xlsx'; | ||||
|     document.body.appendChild(a); | ||||
|     a.click(); | ||||
|     document.body.removeChild(a); | ||||
|     window.URL.revokeObjectURL(link); | ||||
|   } | ||||
| } | ||||
| const rowSave = async (val, done, loading) => { | ||||
|   console.info('新增', val); | ||||
|   let data = {}; | ||||
|   if (selectTreeNode.value.level < 1) { | ||||
|     data.landType = val.landType; | ||||
|   } else { | ||||
|     data = { | ||||
|       pid: selectTreeNode.value.id, | ||||
|       landCategory: val.landCategory, | ||||
|     }; | ||||
|   } | ||||
|   let res = await landTypeSave(data); | ||||
|   if (res.code == 200) { | ||||
|     ElMessage.success('创建成功'); | ||||
|     getLandTree(); | ||||
|     if (selectTreeNode.value.level > 0) loadData(); | ||||
|     done(); | ||||
|   } | ||||
|   // saveOperationRecord(row) | ||||
|   //   .then((res) => { | ||||
|   //     if (res.code === 200) { | ||||
|   //       app.$message.success('添加成功!'); | ||||
|   //       done(); | ||||
|   //       loadData(); | ||||
|   //     } | ||||
|   //   }) | ||||
|   //   .catch((err) => { | ||||
|   //     app.$message.error(err.msg); | ||||
|   //   }) | ||||
|   //   .finally(() => { | ||||
|   //     loading(); | ||||
|   //   }); | ||||
|   loading(); | ||||
| }; | ||||
| 
 | ||||
| const rowUpdate = (row, index, done, loading) => { | ||||
|   console.info('更新'); | ||||
|   console.log('row', row); | ||||
|   editLandType({ | ||||
|     id: row.id, | ||||
|     landCategory: row.landCategory, | ||||
|   }).then((res) => { | ||||
|     if (res.code === 200) { | ||||
|       app.$message.success('更新成功!'); | ||||
|       loadData(); | ||||
|       done(); | ||||
|     } | ||||
|   }); | ||||
|   loading(); | ||||
| }; | ||||
| 
 | ||||
| // #endregion | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .tree_node_ { | ||||
|   padding: 0 6px; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   height: calc(100% - 4px); | ||||
|   border-radius: 2px; | ||||
|   user-select: none; | ||||
| } | ||||
| .nodeActive { | ||||
|   background-color: rgb(172, 223, 243); | ||||
| } | ||||
| ::v-deep() { | ||||
|   .is-current { | ||||
|     .el-tree-node__content { | ||||
|       background-color: rgba($color: #000000, $alpha: 0); | ||||
|     } | ||||
|   } | ||||
|   .el-tree-node__content { | ||||
|     &:hover { | ||||
|       background-color: rgba($color: #000000, $alpha: 0); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,107 +1,96 @@ | ||||
| <template> | ||||
|   <CustomCard> | ||||
|     <div> | ||||
|       <el-row :gutter="20"> | ||||
|         <el-col :span="4"> | ||||
|           <el-tree | ||||
|             style="max-width: 600px" | ||||
|             :data="treeData" | ||||
|             node-key="id" | ||||
|             :default-expanded-keys="[selectTreeNode.id]" | ||||
|             :props="{ value: 'id' }" | ||||
|             :expand-on-click-node="false" | ||||
|             @node-click="handleNodeClick" | ||||
|           > | ||||
|             <template #default="{ data }"> | ||||
|               <div class="tree_node_" :class="{ nodeActive: data.id == selectTreeNode.id || data.id == selectTreeNode.pId }"> | ||||
|                 {{ data.label }} | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-tree> | ||||
|         </el-col> | ||||
|         <el-col :span="20"> | ||||
|           <avue-crud | ||||
|             ref="crudRef" | ||||
|             v-model="state.form" | ||||
|             v-model:search="state.query" | ||||
|             v-model:page="state.pageData" | ||||
|             :table-loading="state.loading" | ||||
|             :data="state.data" | ||||
|             :option="state.options" | ||||
|             @refresh-change="refreshChange" | ||||
|             @search-reset="searchChange" | ||||
|             @search-change="searchChange" | ||||
|             @selection-change="selectionChange" | ||||
|             @current-change="currentChange" | ||||
|             @size-change="sizeChange" | ||||
|             @row-del="rowDel" | ||||
|             @row-save="rowSave" | ||||
|             @row-update="rowUpdate" | ||||
|           > | ||||
|             <template #menu-left> | ||||
|               <el-button type="primary" icon="Plus" @click="onAdd">新增</el-button> | ||||
|               <el-button type="success" icon="download" @click="onExport">导出</el-button> | ||||
|             </template> | ||||
|   <div class="custom-page"> | ||||
|     <el-row :gutter="20"> | ||||
|       <splitpanes class="default-theme"> | ||||
|         <pane size="16"> | ||||
|           <el-col> | ||||
|             <custom-table-tree title="土地用途分类信息" :data="treeData" :option="treeOption" filter @node-click="handleNodeClick"> | ||||
|               <template #default="{ data }"> | ||||
|                 <div :class="{ 'text-primary': data.id == treeSelected.id || data.id == treeSelected.pId }"> | ||||
|                   {{ data.landType }} | ||||
|                 </div> | ||||
|               </template> | ||||
|             </custom-table-tree> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|         <pane size="84"> | ||||
|           <el-col> | ||||
|             <avue-crud | ||||
|               ref="crudRef" | ||||
|               v-model="state.form" | ||||
|               v-model:search="state.query" | ||||
|               v-model:page="state.pageData" | ||||
|               :table-loading="state.loading" | ||||
|               :data="state.data" | ||||
|               :option="state.options" | ||||
|               @refresh-change="refreshChange" | ||||
|               @search-reset="searchChange" | ||||
|               @search-change="searchChange" | ||||
|               @selection-change="selectionChange" | ||||
|               @current-change="currentChange" | ||||
|               @size-change="sizeChange" | ||||
|               @row-del="rowDel" | ||||
|               @row-save="rowSave" | ||||
|               @row-update="rowUpdate" | ||||
|             > | ||||
|               <template #menu-left> | ||||
|                 <el-button type="success" icon="download" @click="onExport">导出</el-button> | ||||
|               </template> | ||||
| 
 | ||||
|             <template #menu="scope"> | ||||
|               <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|             </template> | ||||
|           </avue-crud> | ||||
|         </el-col> | ||||
|       </el-row> | ||||
|     </div> | ||||
|   </CustomCard> | ||||
|               <template #status="{ row }"> | ||||
|                 <el-tag v-if="row.status == 1" type="success">启用</el-tag> | ||||
|                 <el-tag v-if="row.status == 0" type="danger">禁用</el-tag> | ||||
|               </template> | ||||
| 
 | ||||
|               <template #menu="scope"> | ||||
|                 <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|               </template> | ||||
|             </avue-crud> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|       </splitpanes> | ||||
|     </el-row> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, nextTick } from 'vue'; | ||||
| import { ref, reactive, onMounted, nextTick, watch } from 'vue'; | ||||
| import { useApp } from '@/hooks'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| import CustomCard from '@/components/CustomCard.vue'; | ||||
| import { getLandTypeTree, landTypeSave, getLandType, exportLandType, delLandType, editLandType } from '@/apis/baseInfo'; | ||||
| import { ElMessage } from 'element-plus'; | ||||
| import { useUserStore } from '@/store/modules/user'; | ||||
| import { isEmpty, flattenTree, setDicLabel, downloadFile } from '@/utils'; | ||||
| 
 | ||||
| const { VITE_APP_BASE_API } = import.meta.env; | ||||
| const app = useApp(); | ||||
| 
 | ||||
| /* --------------- data --------------- */ | ||||
| // #region | ||||
| const selectTreeNode = ref({ | ||||
|   id: '', | ||||
|   label: '', | ||||
|   pId: '', | ||||
|   pName: '', | ||||
|   level: 0, | ||||
| }); | ||||
| const landTypesDic = ref([]); | ||||
| const UserStore = useUserStore(); | ||||
| const crudRef = ref(null); | ||||
| const treeData = ref([]); | ||||
| const treeOption = ref({ | ||||
|   nodeKey: 'id', | ||||
|   props: { children: 'children', label: 'landType', id: 'id' }, | ||||
| }); | ||||
| const treeSelected = ref({}); | ||||
| const treeDicData = ref([]); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: { | ||||
|     current: 1, | ||||
|     size: 10, | ||||
|   }, | ||||
|   form: {}, | ||||
|   form: { | ||||
|     status: 1, | ||||
|   }, | ||||
|   selection: [], | ||||
|   options: { | ||||
|     ...CRUD_OPTIONS, | ||||
|     addBtnText: '', | ||||
|     addBtn: false, | ||||
|     dialogWidth: 680, | ||||
|     dialogWidth: 600, | ||||
|     selection: false, | ||||
|     refreshBtn: false, | ||||
|     column: [ | ||||
|       { label: '编号', prop: 'id', addDisplay: false, editDisplay: false }, | ||||
|       { | ||||
|         label: '用地分类', | ||||
|         label: '分类名称', | ||||
|         prop: 'landType', | ||||
|         dicData: landTypesDic, | ||||
|         // type: 'select', | ||||
|         multiple: true, | ||||
|         span: 23, | ||||
|         props: { | ||||
|           value: 'id', | ||||
|           label: 'childLandCategory', | ||||
|         }, | ||||
|         span: 24, | ||||
|         rules: [ | ||||
|           { | ||||
|             required: true, | ||||
| @ -109,14 +98,35 @@ const state = reactive({ | ||||
|             trigger: 'blur', | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         label: '用途分类', | ||||
|         prop: 'pid', | ||||
|         display: false, | ||||
|         render: ({ row }) => { | ||||
|           return row.landType; | ||||
|           return setDicLabel(treeDicData.value, row.pid); | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '土地类别', | ||||
|         prop: 'landCategory', | ||||
|         addDisplay: false, | ||||
|         label: '用途分类', | ||||
|         prop: 'pids', | ||||
|         type: 'cascader', | ||||
|         checkStrictly: true, | ||||
|         hide: true, | ||||
|         addDisplay: true, | ||||
|         editDisplay: true, | ||||
|         viewDisplay: false, | ||||
|         props: { | ||||
|           label: 'landType', | ||||
|           value: 'id', | ||||
|           children: 'children', | ||||
|         }, | ||||
|         dicUrl: `${VITE_APP_BASE_API}/land-resource/baseInfo/landTree`, | ||||
|         dicHeaders: { | ||||
|           authorization: UserStore.token, | ||||
|         }, | ||||
|         dicFormatter: (res) => [{ id: null, landType: '土地分类', children: res.data }], | ||||
|         span: 24, | ||||
|         rules: [ | ||||
|           { | ||||
|             required: true, | ||||
| @ -124,16 +134,22 @@ const state = reactive({ | ||||
|             trigger: 'blur', | ||||
|           }, | ||||
|         ], | ||||
|         render: ({ row }) => { | ||||
|           return row.landCategory; | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '状态', | ||||
|         prop: 'status', | ||||
|         render: ({ row }) => { | ||||
|           return row.status == '1' ? '启用' : '禁用'; | ||||
|         }, | ||||
|         type: 'select', | ||||
|         dicData: [ | ||||
|           { | ||||
|             label: '启用', | ||||
|             value: 1, | ||||
|           }, | ||||
|           { | ||||
|             label: '禁用', | ||||
|             value: 0, | ||||
|           }, | ||||
|         ], | ||||
|         value: 1, | ||||
|         addDisplay: false, | ||||
|         editDisplay: false, | ||||
|       }, | ||||
| @ -166,15 +182,35 @@ const state = reactive({ | ||||
|   currentRow: {}, | ||||
| }); | ||||
| 
 | ||||
| const treeData = ref([]); | ||||
| watch( | ||||
|   () => treeData.value, | ||||
|   (val) => { | ||||
|     if (!isEmpty(val)) { | ||||
|       const list = flattenTree(val); | ||||
|       treeDicData.value = list.map((item) => { | ||||
|         return { label: item.landType, value: item.id }; | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| // #endregion | ||||
| const getLandTree = async () => { | ||||
|   try { | ||||
|     const res = await getLandTypeTree(); | ||||
|     if (res.code == 200) { | ||||
|       treeData.value = [{ id: null, landType: '土地分类', children: res.data }]; | ||||
|     } | ||||
|   } catch (err) { | ||||
|     app.$message.error(err.msg); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| getLandTree(); | ||||
| 
 | ||||
| /* --------------- methods --------------- */ | ||||
| const loadData = () => { | ||||
|   state.loading = true; | ||||
|   getLandType({ | ||||
|     pid: selectTreeNode.value.id, | ||||
|     pid: treeSelected.value?.id ?? null, | ||||
|     ...state.query, | ||||
|   }) | ||||
|     .then((res) => { | ||||
| @ -197,34 +233,15 @@ const loadData = () => { | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| const handleNodeClick = (data, node) => { | ||||
|   treeSelected.value = data; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   getLandTree(); | ||||
|   loadData(); | ||||
| }); | ||||
| 
 | ||||
| async function getLandTree() { | ||||
|   let res = await getLandTypeTree(); | ||||
|   if (res.code == 200) { | ||||
|     treeData.value = newTree(res.data, 0); | ||||
|     landTypesDic.value = res.data.map((v) => { | ||||
|       return { | ||||
|         id: v.id, | ||||
|         label: v.prentLandType, | ||||
|       }; | ||||
|     }); | ||||
|     console.log('treeData', treeData.value); | ||||
|   } | ||||
| } | ||||
| function newTree(arr, i) { | ||||
|   arr.forEach((v) => { | ||||
|     if (i == 0) { | ||||
|       v.label = v.prentLandType; | ||||
|     } else { | ||||
|       v.label = v.childLandCategory; | ||||
|     } | ||||
|     if (v.children) v.children = newTree(v.children, i + 1); | ||||
|   }); | ||||
|   return arr; | ||||
| } | ||||
| // 页数 | ||||
| const currentChange = (current) => { | ||||
|   state.query.current = current; | ||||
| @ -257,42 +274,8 @@ const selectionChange = (rows) => { | ||||
|   state.selection = rows; | ||||
| }; | ||||
| 
 | ||||
| const handleNodeClick = (data, node) => { | ||||
|   const { id } = data; | ||||
|   if (selectTreeNode.value.id != id) { | ||||
|     if (node.level < 2) { | ||||
|       selectTreeNode.value = handleNodeData({ data, level: node.level }); | ||||
|     } else selectTreeNode.value = handleNodeData({ data: node.parent.data, level: node.level }); | ||||
|     loadData(); | ||||
|   } else { | ||||
|     selectTreeNode.value = { id: '', label: '', level: 0 }; | ||||
|     state.data = []; | ||||
|   } | ||||
|   if (selectTreeNode.value.level < 1) { | ||||
|     state.options.dialogWidth = 680; | ||||
|     state.options.column[1].span = 23; | ||||
|     state.options.column[2].addDisplay = false; | ||||
|     delete state.options.column[1].addDisabled; | ||||
|     delete state.options.column[1].value; | ||||
|   } else { | ||||
|     state.options.column[2].addDisplay = true; | ||||
|     state.options.column[1].addDisabled = true; | ||||
|     state.options.column[1].value = selectTreeNode.value.label; | ||||
|     delete state.options.dialogWidth; | ||||
|     delete state.options.column[1].type; | ||||
|     delete state.options.column[1].span; | ||||
|   } | ||||
| }; | ||||
| function handleNodeData({ data, level }) { | ||||
|   return { | ||||
|     id: data.id, | ||||
|     label: data.label, | ||||
|     level, | ||||
|   }; | ||||
| } | ||||
| // 编辑状态 | ||||
| // 启用 | ||||
| async function rowStatus(row) { | ||||
|   console.info('操作状态', row.$index); | ||||
|   const { id } = row; | ||||
|   let status = row.status == '1' ? '0' : '1'; | ||||
|   let params = { | ||||
| @ -301,7 +284,7 @@ async function rowStatus(row) { | ||||
|   }; | ||||
|   let res = await editLandType(params); | ||||
|   if (res.code == 200) { | ||||
|     ElMessage.success('操作成功'); | ||||
|     app.$message.success('操作成功!'); | ||||
|     nextTick(() => { | ||||
|       state.data[row.$index].status = status; | ||||
|       loadData(); | ||||
| @ -309,118 +292,85 @@ async function rowStatus(row) { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // 删除 | ||||
| async function rowDel(row, done, loading) { | ||||
|   let res = await delLandType(row.id); | ||||
|   if (res.code === 200) { | ||||
|     app.$message.success('已删除!'); | ||||
|     getLandTree(); | ||||
|     loadData(); | ||||
|     done(); | ||||
|   } | ||||
|   loading(); | ||||
| } | ||||
| 
 | ||||
| const setPid = (row) => { | ||||
|   if (!isEmpty(row.pids)) { | ||||
|     const len = row.pids.length; | ||||
|     row.pid = row?.pids[len - 1] ?? null; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // 新增 | ||||
| const rowSave = async (row, done, loading) => { | ||||
|   setPid(row); | ||||
|   landTypeSave(row) | ||||
|     .then((res) => { | ||||
|       if (res.code === 200) { | ||||
|         app.$message.success('添加成功!'); | ||||
|         done(); | ||||
|         getLandTree(); | ||||
|         loadData(); | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error(err.msg); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       loading(); | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 编辑 | ||||
| const rowEdit = (row) => { | ||||
|   crudRef.value && crudRef.value.rowEdit(row); | ||||
| }; | ||||
| 
 | ||||
| const onAdd = () => { | ||||
|   crudRef.value && crudRef.value.rowAdd(); | ||||
| }; | ||||
| async function onExport() { | ||||
|   console.log('test ---'); | ||||
|   if (selectTreeNode.value.level < 1) return ElMessage.warning('请选择用地分类'); | ||||
|   let res = await exportLandType({ | ||||
|     pid: selectTreeNode.value.id, | ||||
|   }); | ||||
|   console.log('edxport', res); | ||||
|   if (res.status == 200) { | ||||
|     let a = document.createElement('a'); | ||||
|     let blob = new Blob([res.data]); | ||||
|     let link = window.URL.createObjectURL(blob); | ||||
|     a.href = link; | ||||
|     a.download = '用地分类.xlsx'; | ||||
|     document.body.appendChild(a); | ||||
|     a.click(); | ||||
|     document.body.removeChild(a); | ||||
|     window.URL.revokeObjectURL(link); | ||||
|   } | ||||
| } | ||||
| const rowSave = async (val, done, loading) => { | ||||
|   console.info('新增', val); | ||||
|   let data = {}; | ||||
|   if (selectTreeNode.value.level < 1) { | ||||
|     data.landType = val.landType; | ||||
|   } else { | ||||
|     data = { | ||||
|       pid: selectTreeNode.value.id, | ||||
|       landCategory: val.landCategory, | ||||
|     }; | ||||
|   } | ||||
|   let res = await landTypeSave(data); | ||||
|   if (res.code == 200) { | ||||
|     ElMessage.success('创建成功'); | ||||
|     getLandTree(); | ||||
|     if (selectTreeNode.value.level > 0) loadData(); | ||||
|     done(); | ||||
|   } | ||||
|   // saveOperationRecord(row) | ||||
|   //   .then((res) => { | ||||
|   //     if (res.code === 200) { | ||||
|   //       app.$message.success('添加成功!'); | ||||
|   //       done(); | ||||
|   //       loadData(); | ||||
|   //     } | ||||
|   //   }) | ||||
|   //   .catch((err) => { | ||||
|   //     app.$message.error(err.msg); | ||||
|   //   }) | ||||
|   //   .finally(() => { | ||||
|   //     loading(); | ||||
|   //   }); | ||||
|   loading(); | ||||
| }; | ||||
| 
 | ||||
| const rowUpdate = (row, index, done, loading) => { | ||||
|   console.info('更新'); | ||||
|   console.log('row', row); | ||||
|   editLandType({ | ||||
|     id: row.id, | ||||
|     landCategory: row.landCategory, | ||||
|   }).then((res) => { | ||||
|   setPid(row); | ||||
|   editLandType(row).then((res) => { | ||||
|     if (res.code === 200) { | ||||
|       app.$message.success('更新成功!'); | ||||
|       loadData(); | ||||
|       getLandTree(); | ||||
|       done(); | ||||
|     } | ||||
|   }); | ||||
|   loading(); | ||||
| }; | ||||
| 
 | ||||
| // #endregion | ||||
| // 导出 | ||||
| const onExport = () => { | ||||
|   if (isEmpty(state.data)) { | ||||
|     app.$message.error('请先选择用地分类!'); | ||||
|     return; | ||||
|   } | ||||
|   state.loading = true; | ||||
|   const fileName = '用地分类.xlsx'; | ||||
|   exportLandType({ | ||||
|     pid: treeSelected.value.id, | ||||
|   }) | ||||
|     .then((res) => { | ||||
|       if (res.status === 200) { | ||||
|         downloadFile(res.data, fileName, 'blob'); | ||||
|         app.$message.success('导出成功!'); | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error('导出失败!'); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       state.loading = false; | ||||
|     }); | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .tree_node_ { | ||||
|   padding: 0 6px; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   height: calc(100% - 4px); | ||||
|   border-radius: 2px; | ||||
|   user-select: none; | ||||
| } | ||||
| .nodeActive { | ||||
|   background-color: rgb(172, 223, 243); | ||||
| } | ||||
| ::v-deep() { | ||||
|   .is-current { | ||||
|     .el-tree-node__content { | ||||
|       background-color: rgba($color: #000000, $alpha: 0); | ||||
|     } | ||||
|   } | ||||
|   .el-tree-node__content { | ||||
|     &:hover { | ||||
|       background-color: rgba($color: #000000, $alpha: 0); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -1,53 +1,49 @@ | ||||
| <template> | ||||
|   <CustomCard> | ||||
|     <div> | ||||
|       <el-row :gutter="20"> | ||||
|         <el-col :span="4"> | ||||
|           <!-- <el-tree | ||||
|             style="max-width: 600px" | ||||
|             :data="typeTree" | ||||
|             node-key="areaCode" | ||||
|             :props="{ children: 'areaChildVOS', label: 'areaName' }" | ||||
|             @node-click="handleNodeClick" | ||||
|           /> --> | ||||
|           <custom-table-tree title="行政区域" :data="typeTree" :option="treeOption" @node-click="handleNodeClick" /> | ||||
|         </el-col> | ||||
|         <el-col :span="20"> | ||||
|           <avue-crud | ||||
|             ref="crudRef" | ||||
|             v-model="state.form" | ||||
|             v-model:search="state.query" | ||||
|             v-model:page="state.pageData" | ||||
|             :table-loading="state.loading" | ||||
|             :data="state.data" | ||||
|             :option="state.options" | ||||
|             @refresh-change="refreshChange" | ||||
|             @search-reset="searchChange" | ||||
|             @search-change="searchChange" | ||||
|             @selection-change="selectionChange" | ||||
|             @current-change="currentChange" | ||||
|             @size-change="sizeChange" | ||||
|             @row-del="rowDel" | ||||
|           > | ||||
|             <template #menu-left> | ||||
|               <el-button type="primary" icon="Plus" @click="onAdd">新增</el-button> | ||||
|               <el-button type="success" icon="download" @click="onExport">导出</el-button> | ||||
|             </template> | ||||
|   <div class="custom-page"> | ||||
|     <el-row :gutter="20"> | ||||
|       <splitpanes class="default-theme"> | ||||
|         <pane size="16"> | ||||
|           <el-col> | ||||
|             <custom-table-tree title="行政区域" :data="typeTree" :option="treeOption" @node-click="handleNodeClick" /> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|         <pane size="84"> | ||||
|           <el-col> | ||||
|             <avue-crud | ||||
|               ref="crudRef" | ||||
|               v-model="state.form" | ||||
|               v-model:search="state.query" | ||||
|               v-model:page="state.pageData" | ||||
|               :table-loading="state.loading" | ||||
|               :data="state.data" | ||||
|               :option="state.options" | ||||
|               @refresh-change="refreshChange" | ||||
|               @search-reset="searchChange" | ||||
|               @search-change="searchChange" | ||||
|               @selection-change="selectionChange" | ||||
|               @current-change="currentChange" | ||||
|               @size-change="sizeChange" | ||||
|               @row-del="rowDel" | ||||
|             > | ||||
|               <template #menu-left> | ||||
|                 <el-button type="primary" icon="Plus" @click="onAdd">新增</el-button> | ||||
|                 <el-button type="success" icon="download" @click="onExport">导出</el-button> | ||||
|               </template> | ||||
| 
 | ||||
|             <template #menu="scope"> | ||||
|               <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|             </template> | ||||
|           </avue-crud> | ||||
|         </el-col> | ||||
|       </el-row> | ||||
|     </div> | ||||
|   </CustomCard> | ||||
|               <template #menu="scope"> | ||||
|                 <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|               </template> | ||||
|             </avue-crud> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|       </splitpanes> | ||||
|     </el-row> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| import { useApp } from '@/hooks'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| import CustomCard from '@/components/CustomCard.vue'; | ||||
| import { useUserStore } from '@/store/modules/user'; | ||||
| import { getRegion } from '@/apis/index'; | ||||
| 
 | ||||
| @ -55,9 +51,6 @@ const { VITE_APP_BASE_API } = import.meta.env; | ||||
| const app = useApp(); | ||||
| const UserStore = useUserStore(); | ||||
| 
 | ||||
| /* --------------- data --------------- */ | ||||
| // #region | ||||
| 
 | ||||
| const crudRef = ref(null); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
| @ -139,9 +132,6 @@ const infoData = reactive({ | ||||
|   name: '', | ||||
| }); | ||||
| 
 | ||||
| // #endregion | ||||
| 
 | ||||
| /* --------------- methods --------------- */ | ||||
| const loadData = () => { | ||||
|   //state.loading = true; | ||||
|   // getAnnualList(state.query) | ||||
| @ -256,9 +246,4 @@ const onAdd = () => { | ||||
|   crudRef.value && crudRef.value.rowAdd(); | ||||
| }; | ||||
| const onExport = () => {}; | ||||
| // #region | ||||
| 
 | ||||
| // #endregion | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped></style> | ||||
|  | ||||
| @ -74,7 +74,7 @@ const state = reactive({ | ||||
|   areaOption: { | ||||
|     // color: ['#fed500'], | ||||
|     title: { | ||||
|       text: '土地分别数据统计', | ||||
|       text: '土地分布数据统计', | ||||
|       textStyle: { | ||||
|         color: '#333', | ||||
|       }, | ||||
|  | ||||
| @ -30,14 +30,14 @@ | ||||
|         <el-button type="success" icon="download" @click="handleExport">导出</el-button> | ||||
|         <el-button type="success" icon="upload" @click="onUpload">导入</el-button> | ||||
|       </template> | ||||
|       <template #menu="{ row }"> | ||||
|       <!-- <template #menu="{ row }"> | ||||
|         <el-button type="info" link @click="handleView(row)">查看</el-button> | ||||
|         <el-popconfirm title="确定删除该土地?" @confirm="() => handleDelete(row.id)"> | ||||
|           <template #reference> | ||||
|             <el-button type="danger" link>删除</el-button> | ||||
|           </template> | ||||
|         </el-popconfirm> | ||||
|       </template> | ||||
|       </template> --> | ||||
|       <template #area-form> | ||||
|         <section class="area_form_"> | ||||
|           <el-input-number v-model="landArea" :precision="2" :step="1" :min="1" controls-position="right"></el-input-number> | ||||
| @ -58,7 +58,12 @@ | ||||
|       <template #landUrl-form="{ type }"> | ||||
|         <Attrs v-model:attrs="landAttrs" :type="type" /> | ||||
|       </template> | ||||
| 
 | ||||
|       <template #menu="scope"> | ||||
|         <custom-table-operate :actions="option.actions" :data="scope" /> | ||||
|       </template> | ||||
|     </avue-crud> | ||||
| 
 | ||||
|     <custom-import-excel | ||||
|       ref="importExcelRef" | ||||
|       :template-url="getAssetsFile('template/土地模版表.xlsx')" | ||||
| @ -416,6 +421,24 @@ const option = reactive({ | ||||
|       ], | ||||
|     }, | ||||
|   ], | ||||
|   actions: [ | ||||
|     { | ||||
|       name: '查看', | ||||
|       icon: 'view', | ||||
|       event: ({ row }) => handleView(row), | ||||
|     }, | ||||
|     // { | ||||
|     //   name: '编辑', | ||||
|     //   icon: 'edit', | ||||
|     //   event: ({ row }) => rowEdit(row), | ||||
|     // }, | ||||
|     { | ||||
|       type: 'danger', | ||||
|       name: '删除', | ||||
|       icon: 'delete', | ||||
|       event: ({ row }) => handleDelete(row.id), | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| const searchData = reactive({ | ||||
|   landName: '', | ||||
| @ -495,11 +518,26 @@ async function handleExport() { | ||||
|     window.URL.revokeObjectURL(link); | ||||
|   } | ||||
| } | ||||
| async function handleDelete(id) { | ||||
|   let res = await delLand(id); | ||||
|   if (res.code == 200) { | ||||
|     getList(); | ||||
|   } | ||||
| function handleDelete(id) { | ||||
|   app | ||||
|     .$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', { | ||||
|       confirmButtonText: '确定', | ||||
|       cancelButtonText: '取消', | ||||
|       type: 'warning', | ||||
|     }) | ||||
|     .then(() => { | ||||
|       delLand(id) | ||||
|         .then((res) => { | ||||
|           if (res.code === 200) { | ||||
|             app.$message.success('删除成功!'); | ||||
|             getList(); | ||||
|           } | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           app.$message.error(err.msg); | ||||
|         }); | ||||
|     }) | ||||
|     .catch(() => {}); | ||||
| } | ||||
| function handleView(obj) { | ||||
|   rowData.value = obj; | ||||
|  | ||||
| @ -1,36 +1,48 @@ | ||||
| <template> | ||||
|   <div class="custom-page"> | ||||
|     <el-row :gutter="20"> | ||||
|       <el-col :span="4"> | ||||
|         <custom-table-tree title="土地分类" :data="landTypeData" @node-click="onNodeClick" /> | ||||
|       </el-col> | ||||
|       <el-col :span="20"> | ||||
|         <avue-crud | ||||
|           ref="crudRef" | ||||
|           v-model="state.form" | ||||
|           v-model:search="state.query" | ||||
|           v-model:page="state.pageData" | ||||
|           :table-loading="state.loading" | ||||
|           :data="state.data" | ||||
|           :option="state.options" | ||||
|           @refresh-change="refreshChange" | ||||
|           @search-reset="searchChange" | ||||
|           @search-change="searchChange" | ||||
|           @selection-change="selectionChange" | ||||
|           @current-change="currentChange" | ||||
|           @size-change="sizeChange" | ||||
|           @row-del="rowDel" | ||||
|           @row-save="rowSave" | ||||
|           @row-update="rowUpdate" | ||||
|         > | ||||
|           <template #menu-left> | ||||
|             <el-button type="primary" icon="plus" @click="onThreshold">阀值设置</el-button> | ||||
|           </template> | ||||
|           <template #menu="scope"> | ||||
|             <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|           </template> | ||||
|         </avue-crud> | ||||
|       </el-col> | ||||
|       <splitpanes class="default-theme"> | ||||
|         <pane size="16"> | ||||
|           <el-col> | ||||
|             <custom-table-tree title="土地分类" :data="treeData" :option="treeOption" filter @node-click="handleNodeClick"> | ||||
|               <template #default="{ data }"> | ||||
|                 <div :class="{ 'text-primary': data.id == treeSelected.id || data.id == treeSelected.pId }"> | ||||
|                   {{ data.landType }} | ||||
|                 </div> | ||||
|               </template> | ||||
|             </custom-table-tree> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|         <pane size="84"> | ||||
|           <el-col> | ||||
|             <avue-crud | ||||
|               ref="crudRef" | ||||
|               v-model="state.form" | ||||
|               v-model:search="state.query" | ||||
|               v-model:page="state.pageData" | ||||
|               :table-loading="state.loading" | ||||
|               :data="state.data" | ||||
|               :option="state.options" | ||||
|               @refresh-change="refreshChange" | ||||
|               @search-reset="searchChange" | ||||
|               @search-change="searchChange" | ||||
|               @selection-change="selectionChange" | ||||
|               @current-change="currentChange" | ||||
|               @size-change="sizeChange" | ||||
|               @row-del="rowDel" | ||||
|               @row-save="rowSave" | ||||
|               @row-update="rowUpdate" | ||||
|             > | ||||
|               <template #menu-left> | ||||
|                 <el-button type="primary" icon="plus" @click="onThreshold">阀值设置</el-button> | ||||
|               </template> | ||||
|               <template #menu="scope"> | ||||
|                 <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|               </template> | ||||
|             </avue-crud> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|       </splitpanes> | ||||
|     </el-row> | ||||
|   </div> | ||||
| 
 | ||||
| @ -44,42 +56,14 @@ import { useUserStore } from '@/store/modules/user'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| import { mockData, sleep } from '@/utils'; | ||||
| import CustomInfo from './info.vue'; | ||||
| import { getLandTypeTree } from '@/apis/baseInfo'; | ||||
| 
 | ||||
| const { VITE_APP_BASE_API, VITE_APP_NAME } = import.meta.env; | ||||
| const app = useApp(); | ||||
| const UserStore = useUserStore(); | ||||
| const router = useRouter(); | ||||
| const crudRef = ref(null); | ||||
| const landTypeData = ref([ | ||||
|   { | ||||
|     label: '农用地', | ||||
|     id: '0', | ||||
|     children: [ | ||||
|       { label: '耕地', id: '01', children: [], pId: '0' }, | ||||
|       { label: '林地', children: [], id: '02', pId: '0' }, | ||||
|       { label: '草地', children: [], id: '03', pId: '0' }, | ||||
|       { label: '农田水利用地', children: [], id: '04', pId: '0' }, | ||||
|       { label: '养殖水面', children: [], id: '05', pId: '0' }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     label: '建设用地', | ||||
|     id: '1', | ||||
|     children: [ | ||||
|       { label: '城乡住宅用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '公共设施用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '工矿仓储用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '交通水利设施用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '旅游用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '军事设施用地', children: [], id: '11', pId: '10' }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     label: '未利用地', | ||||
|     id: '2', | ||||
|     children: [], | ||||
|   }, | ||||
| ]); | ||||
| 
 | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: { | ||||
| @ -271,6 +255,31 @@ const state = reactive({ | ||||
|   currentRow: {}, | ||||
| }); | ||||
| 
 | ||||
| // tree | ||||
| const treeData = ref([]); | ||||
| const treeOption = ref({ | ||||
|   nodeKey: 'id', | ||||
|   props: { children: 'children', label: 'landType', id: 'id' }, | ||||
| }); | ||||
| const treeSelected = ref({}); | ||||
| 
 | ||||
| const getLandTree = async () => { | ||||
|   try { | ||||
|     const res = await getLandTypeTree(); | ||||
|     if (res.code == 200) { | ||||
|       treeData.value = res.data; | ||||
|     } | ||||
|   } catch (err) { | ||||
|     app.$message.error(err.msg); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const handleNodeClick = (data) => { | ||||
|   treeSelected.value = data; | ||||
| }; | ||||
| 
 | ||||
| getLandTree(); | ||||
| 
 | ||||
| const loadData = async () => { | ||||
|   //state.loading = true; | ||||
|   // GetEntityList(state.query) | ||||
|  | ||||
| @ -1,96 +1,102 @@ | ||||
| <template> | ||||
|   <div class="custom-page"> | ||||
|     <el-row :gutter="20"> | ||||
|       <el-col :span="4"> | ||||
|         <custom-table-tree title="疫病分类" :data="landTypeData" @node-click="onNodeClick" /> | ||||
|       </el-col> | ||||
|       <el-col :span="20"> | ||||
|         <avue-crud | ||||
|           ref="crudRef" | ||||
|           v-model="state.form" | ||||
|           v-model:search="state.query" | ||||
|           v-model:page="state.pageData" | ||||
|           :table-loading="state.loading" | ||||
|           :data="state.data" | ||||
|           :option="state.options" | ||||
|           @refresh-change="refreshChange" | ||||
|           @search-reset="searchChange" | ||||
|           @search-change="searchChange" | ||||
|           @selection-change="selectionChange" | ||||
|           @current-change="currentChange" | ||||
|           @size-change="sizeChange" | ||||
|           @row-del="rowDel" | ||||
|           @row-save="rowSave" | ||||
|           @row-update="rowUpdate" | ||||
|         > | ||||
|           <template #menu-left> | ||||
|             <el-button type="primary" icon="plus" @click="rowAdd">添加</el-button> | ||||
|             <el-button type="danger" icon="delete" @click="onDel(state.selection)">批量删除</el-button> | ||||
|           </template> | ||||
| 
 | ||||
|           <template #reportUrl-form="{ column, value }"> | ||||
|             <el-upload | ||||
|               v-model:file-list="state.fileList" | ||||
|               action="#" | ||||
|               :show-file-list="true" | ||||
|               list-type="picture-card" | ||||
|               accept="image/*" | ||||
|               :http-request="rowUploadPicture" | ||||
|       <splitpanes class="default-theme"> | ||||
|         <pane size="16"> | ||||
|           <el-col> | ||||
|             <custom-table-tree title="疫病分类" :data="treeData" @node-click="onNodeClick" /> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|         <pane size="84"> | ||||
|           <el-col> | ||||
|             <avue-crud | ||||
|               ref="crudRef" | ||||
|               v-model="state.form" | ||||
|               v-model:search="state.query" | ||||
|               v-model:page="state.pageData" | ||||
|               :table-loading="state.loading" | ||||
|               :data="state.data" | ||||
|               :option="state.options" | ||||
|               @refresh-change="refreshChange" | ||||
|               @search-reset="searchChange" | ||||
|               @search-change="searchChange" | ||||
|               @selection-change="selectionChange" | ||||
|               @current-change="currentChange" | ||||
|               @size-change="sizeChange" | ||||
|               @row-del="rowDel" | ||||
|               @row-save="rowSave" | ||||
|               @row-update="rowUpdate" | ||||
|             > | ||||
|               <el-icon><Plus /></el-icon> | ||||
|             </el-upload> | ||||
|           </template> | ||||
|               <template #menu-left> | ||||
|                 <el-button type="primary" icon="plus" @click="rowAdd">添加</el-button> | ||||
|                 <el-button type="danger" icon="delete" @click="onDel(state.selection)">批量删除</el-button> | ||||
|               </template> | ||||
| 
 | ||||
|           <template #reportLink-form="{ column, value }"> | ||||
|             <el-button type="primary" text @click="downloadFile(value, `${state.currentRow?.name}-检测报告.png`, 'image')"> 下载 </el-button> | ||||
|           </template> | ||||
|               <template #reportUrl-form="{ column, value }"> | ||||
|                 <el-upload | ||||
|                   v-model:file-list="state.fileList" | ||||
|                   action="#" | ||||
|                   :show-file-list="true" | ||||
|                   list-type="picture-card" | ||||
|                   accept="image/*" | ||||
|                   :http-request="rowUploadPicture" | ||||
|                 > | ||||
|                   <el-icon><Plus /></el-icon> | ||||
|                 </el-upload> | ||||
|               </template> | ||||
| 
 | ||||
|           <template #result-form="{ column, value }"> | ||||
|             <el-button type="primary" style="margin-bottom: 16px" @click="addInfo(value)">新增</el-button> | ||||
|             <el-table :data="value" style="width: 100%" border> | ||||
|               <el-table-column prop="c1" label="检测项目" align="center"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-input v-model="scope.row.c1" :disabled="scope.row.disabled" /> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column prop="c2" label="检测方法" align="center"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-input v-model="scope.row.c2" :disabled="scope.row.disabled" /> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column prop="c3" label="主要试剂" align="center"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-input v-model="scope.row.c3" :disabled="scope.row.disabled" /> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column prop="c4" label="检测结果" align="center"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-input v-model="scope.row.c4" :disabled="scope.row.disabled" /> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column prop="c5" label="备注" align="center"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-input v-model="scope.row.c5" type="textarea" rows="2" :disabled="scope.row.disabled" /> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|               <el-table-column label="操作" width="130" align="center"> | ||||
|                 <template #default="scope"> | ||||
|                   <el-button type="primary" icon="edit" text @click="editInfo(scope.row)"></el-button> | ||||
|                   <el-button type="danger" icon="delete" text @click="delInfo(value, scope.row, scope.$index)"></el-button> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </el-table> | ||||
|           </template> | ||||
|               <template #reportLink-form="{ column, value }"> | ||||
|                 <el-button type="primary" text @click="downloadFile(value, `${state.currentRow?.name}-检测报告.png`, 'image')"> 下载 </el-button> | ||||
|               </template> | ||||
| 
 | ||||
|           <template #customInfo-form="{ column }"> | ||||
|             <custom-info :row="state.currentRow" /> | ||||
|           </template> | ||||
|               <template #result-form="{ column, value }"> | ||||
|                 <el-button type="primary" style="margin-bottom: 16px" @click="addInfo(value)">新增</el-button> | ||||
|                 <el-table :data="value" style="width: 100%" border> | ||||
|                   <el-table-column prop="c1" label="检测项目" align="center"> | ||||
|                     <template #default="scope"> | ||||
|                       <el-input v-model="scope.row.c1" :disabled="scope.row.disabled" /> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                   <el-table-column prop="c2" label="检测方法" align="center"> | ||||
|                     <template #default="scope"> | ||||
|                       <el-input v-model="scope.row.c2" :disabled="scope.row.disabled" /> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                   <el-table-column prop="c3" label="主要试剂" align="center"> | ||||
|                     <template #default="scope"> | ||||
|                       <el-input v-model="scope.row.c3" :disabled="scope.row.disabled" /> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                   <el-table-column prop="c4" label="检测结果" align="center"> | ||||
|                     <template #default="scope"> | ||||
|                       <el-input v-model="scope.row.c4" :disabled="scope.row.disabled" /> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                   <el-table-column prop="c5" label="备注" align="center"> | ||||
|                     <template #default="scope"> | ||||
|                       <el-input v-model="scope.row.c5" type="textarea" rows="2" :disabled="scope.row.disabled" /> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                   <el-table-column label="操作" width="130" align="center"> | ||||
|                     <template #default="scope"> | ||||
|                       <el-button type="primary" icon="edit" text @click="editInfo(scope.row)"></el-button> | ||||
|                       <el-button type="danger" icon="delete" text @click="delInfo(value, scope.row, scope.$index)"></el-button> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                 </el-table> | ||||
|               </template> | ||||
| 
 | ||||
|           <template #menu="scope"> | ||||
|             <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|           </template> | ||||
|         </avue-crud> | ||||
|       </el-col> | ||||
|               <template #customInfo-form="{ column }"> | ||||
|                 <custom-info :row="state.currentRow" /> | ||||
|               </template> | ||||
| 
 | ||||
|               <template #menu="scope"> | ||||
|                 <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|               </template> | ||||
|             </avue-crud> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|       </splitpanes> | ||||
|     </el-row> | ||||
|   </div> | ||||
| </template> | ||||
| @ -108,18 +114,6 @@ const app = useApp(); | ||||
| const UserStore = useUserStore(); | ||||
| const router = useRouter(); | ||||
| const crudRef = ref(null); | ||||
| const landTypeData = ref([ | ||||
|   // { | ||||
|   // label: '疫病分类', | ||||
|   // id: '0', | ||||
|   // children: [ | ||||
|   { label: '家禽类', id: '01', children: [], pId: '0' }, | ||||
|   { label: '家畜类', id: '02', children: [], pId: '0' }, | ||||
|   { label: '水产类', id: '03', children: [], pId: '0' }, | ||||
|   { label: '特种养殖类', id: '04', children: [], pId: '0' }, | ||||
|   //   ], | ||||
|   // }, | ||||
| ]); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: { | ||||
| @ -377,6 +371,20 @@ const state = reactive({ | ||||
|   currentRow: {}, | ||||
| }); | ||||
| 
 | ||||
| // tree | ||||
| const treeData = ref([ | ||||
|   // { | ||||
|   // label: '疫病分类', | ||||
|   // id: '0', | ||||
|   // children: [ | ||||
|   { label: '家禽类', id: '01', children: [], pId: '0' }, | ||||
|   { label: '家畜类', id: '02', children: [], pId: '0' }, | ||||
|   { label: '水产类', id: '03', children: [], pId: '0' }, | ||||
|   { label: '特种养殖类', id: '04', children: [], pId: '0' }, | ||||
|   //   ], | ||||
|   // }, | ||||
| ]); | ||||
| 
 | ||||
| const loadData = async () => { | ||||
|   //state.loading = true; | ||||
|   // GetEntityList(state.query) | ||||
|  | ||||
| @ -1,33 +1,45 @@ | ||||
| <template> | ||||
|   <div class="custom-page"> | ||||
|     <el-row :gutter="20"> | ||||
|       <el-col :span="4"> | ||||
|         <custom-table-tree title="土地分类" :data="landTypeData" @node-click="onNodeClick" /> | ||||
|       </el-col> | ||||
|       <el-col :span="20"> | ||||
|         <avue-crud | ||||
|           ref="crudRef" | ||||
|           v-model="state.form" | ||||
|           v-model:search="state.query" | ||||
|           v-model:page="state.pageData" | ||||
|           :table-loading="state.loading" | ||||
|           :data="state.data" | ||||
|           :option="state.options" | ||||
|           @refresh-change="refreshChange" | ||||
|           @search-reset="searchChange" | ||||
|           @search-change="searchChange" | ||||
|           @selection-change="selectionChange" | ||||
|           @current-change="currentChange" | ||||
|           @size-change="sizeChange" | ||||
|           @row-del="rowDel" | ||||
|           @row-save="rowSave" | ||||
|           @row-update="rowUpdate" | ||||
|         > | ||||
|           <template #menu="scope"> | ||||
|             <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|           </template> | ||||
|         </avue-crud> | ||||
|       </el-col> | ||||
|       <splitpanes class="default-theme"> | ||||
|         <pane size="16"> | ||||
|           <el-col> | ||||
|             <custom-table-tree title="土地分类" :data="treeData" :option="treeOption" filter @node-click="handleNodeClick"> | ||||
|               <template #default="{ data }"> | ||||
|                 <div :class="{ 'text-primary': data.id == treeSelected.id || data.id == treeSelected.pId }"> | ||||
|                   {{ data.landType }} | ||||
|                 </div> | ||||
|               </template> | ||||
|             </custom-table-tree> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|         <pane size="84"> | ||||
|           <el-col> | ||||
|             <avue-crud | ||||
|               ref="crudRef" | ||||
|               v-model="state.form" | ||||
|               v-model:search="state.query" | ||||
|               v-model:page="state.pageData" | ||||
|               :table-loading="state.loading" | ||||
|               :data="state.data" | ||||
|               :option="state.options" | ||||
|               @refresh-change="refreshChange" | ||||
|               @search-reset="searchChange" | ||||
|               @search-change="searchChange" | ||||
|               @selection-change="selectionChange" | ||||
|               @current-change="currentChange" | ||||
|               @size-change="sizeChange" | ||||
|               @row-del="rowDel" | ||||
|               @row-save="rowSave" | ||||
|               @row-update="rowUpdate" | ||||
|             > | ||||
|               <template #menu="scope"> | ||||
|                 <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|               </template> | ||||
|             </avue-crud> | ||||
|           </el-col> | ||||
|         </pane> | ||||
|       </splitpanes> | ||||
|     </el-row> | ||||
|   </div> | ||||
| 
 | ||||
| @ -41,42 +53,13 @@ import { useUserStore } from '@/store/modules/user'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| import { mockData, sleep } from '@/utils'; | ||||
| import CustomInfo from './info.vue'; | ||||
| import { getLandTypeTree } from '@/apis/baseInfo'; | ||||
| 
 | ||||
| const { VITE_APP_BASE_API, VITE_APP_NAME } = import.meta.env; | ||||
| const app = useApp(); | ||||
| const UserStore = useUserStore(); | ||||
| const router = useRouter(); | ||||
| const crudRef = ref(null); | ||||
| const landTypeData = ref([ | ||||
|   { | ||||
|     label: '农用地', | ||||
|     id: '0', | ||||
|     children: [ | ||||
|       { label: '耕地', id: '01', children: [], pId: '0' }, | ||||
|       { label: '林地', children: [], id: '02', pId: '0' }, | ||||
|       { label: '草地', children: [], id: '03', pId: '0' }, | ||||
|       { label: '农田水利用地', children: [], id: '04', pId: '0' }, | ||||
|       { label: '养殖水面', children: [], id: '05', pId: '0' }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     label: '建设用地', | ||||
|     id: '1', | ||||
|     children: [ | ||||
|       { label: '城乡住宅用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '公共设施用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '工矿仓储用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '交通水利设施用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '旅游用地', children: [], id: '11', pId: '10' }, | ||||
|       { label: '军事设施用地', children: [], id: '11', pId: '10' }, | ||||
|     ], | ||||
|   }, | ||||
|   { | ||||
|     label: '未利用地', | ||||
|     id: '2', | ||||
|     children: [], | ||||
|   }, | ||||
| ]); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: { | ||||
| @ -268,6 +251,31 @@ const state = reactive({ | ||||
|   currentRow: {}, | ||||
| }); | ||||
| 
 | ||||
| // tree | ||||
| const treeData = ref([]); | ||||
| const treeOption = ref({ | ||||
|   nodeKey: 'id', | ||||
|   props: { children: 'children', label: 'landType', id: 'id' }, | ||||
| }); | ||||
| const treeSelected = ref({}); | ||||
| 
 | ||||
| const getLandTree = async () => { | ||||
|   try { | ||||
|     const res = await getLandTypeTree(); | ||||
|     if (res.code == 200) { | ||||
|       treeData.value = res.data; | ||||
|     } | ||||
|   } catch (err) { | ||||
|     app.$message.error(err.msg); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const handleNodeClick = (data) => { | ||||
|   treeSelected.value = data; | ||||
| }; | ||||
| 
 | ||||
| getLandTree(); | ||||
| 
 | ||||
| const loadData = async () => { | ||||
|   //state.loading = true; | ||||
|   // GetEntityList(state.query) | ||||
|  | ||||
| @ -1,206 +0,0 @@ | ||||
| <template> | ||||
|   <div class="custom-page"> | ||||
|     <avue-crud | ||||
|       ref="crudRef" | ||||
|       v-model="state.form" | ||||
|       v-model:search="state.query" | ||||
|       v-model:page="state.page" | ||||
|       :table-loading="state.loading" | ||||
|       :data="state.data" | ||||
|       :option="state.options" | ||||
|       @refresh-change="refreshChange" | ||||
|       @search-reset="searchChange" | ||||
|       @search-change="searchChange" | ||||
|       @row-click="rowClick" | ||||
|       @row-save="rowSave" | ||||
|       @row-update="rowUpdate" | ||||
|       @row-del="rowDel" | ||||
|     > | ||||
|       <template #menu="scope"> | ||||
|         <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|       </template> | ||||
|     </avue-crud> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { reactive, ref } from 'vue'; | ||||
| import { useApp } from '@/hooks'; | ||||
| import { sleep } from '@/utils'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| 
 | ||||
| import Mock from 'mockjs'; | ||||
| const res = Mock.mock({ | ||||
|   'data|20': [ | ||||
|     { | ||||
|       id: '@increment(100000)', | ||||
|       name: '@ctitle(5,10)', | ||||
|       'area|100-1000': 100, | ||||
|       type: '耕地', | ||||
|       tag: '龙津河周边', | ||||
|       address: '耿马镇白塔社区', | ||||
|       createTime: '@datetime("yyyy-MM-dd HH:mm:ss")', | ||||
|       updateTime: '@datetime("yyyy-MM-dd HH:mm:ss")', | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| 
 | ||||
| const app = useApp(); | ||||
| const crudRef = ref(null); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: {}, | ||||
|   form: {}, | ||||
|   options: { | ||||
|     ...CRUD_OPTIONS, | ||||
|     delBtn: false, | ||||
|     column: [ | ||||
|       { | ||||
|         label: '土地编号', | ||||
|         prop: 'id', | ||||
|         fixed: true, | ||||
|         display: false, | ||||
|       }, | ||||
|       { | ||||
|         label: '土地名称', | ||||
|         prop: 'name', | ||||
|         fixed: true, | ||||
|         search: true, | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '土地面积', | ||||
|         prop: 'area', | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '土地类型', | ||||
|         prop: 'type', | ||||
|       }, | ||||
|       { | ||||
|         label: '坐落位置', | ||||
|         prop: 'tag', | ||||
|         type: 'textarea', | ||||
|         width: 200, | ||||
|         span: 24, | ||||
|         rows: 4, | ||||
|         overHidden: true, | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '区域', | ||||
|         prop: 'address', | ||||
|         type: 'textarea', | ||||
|         width: 200, | ||||
|         span: 24, | ||||
|         rows: 4, | ||||
|         overHidden: true, | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '信息录入时间', | ||||
|         prop: 'createTime', | ||||
|         type: 'datetime', | ||||
|         format: 'YYYY-MM-DD HH:mm:ss', | ||||
|         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||
|         width: 200, | ||||
|         display: false, | ||||
|       }, | ||||
|       { | ||||
|         label: '信息更新时间', | ||||
|         prop: 'updateTime', | ||||
|         type: 'datetime', | ||||
|         format: 'YYYY-MM-DD HH:mm:ss', | ||||
|         valueFormat: 'YYYY-MM-DD HH:mm:ss', | ||||
|         width: 200, | ||||
|         display: false, | ||||
|       }, | ||||
|     ], | ||||
|     actions: [ | ||||
|       { | ||||
|         name: '查看', | ||||
|         icon: 'view', | ||||
|         event: ({ row }) => rowView(row), | ||||
|       }, | ||||
|       { | ||||
|         name: '编辑', | ||||
|         icon: 'edit', | ||||
|         event: ({ row }) => rowEdit(row), | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   page: { | ||||
|     total: 0, | ||||
|     currentPage: 1, | ||||
|     pageSize: 10, | ||||
|   }, | ||||
|   data: [], | ||||
| }); | ||||
| 
 | ||||
| const loadData = async () => { | ||||
|   state.loading = true; | ||||
|   await sleep(500); | ||||
|   state.data = res.data; | ||||
|   state.page = { | ||||
|     total: 20, | ||||
|     currentPage: 1, | ||||
|     pageSize: 10, | ||||
|   }; | ||||
|   state.loading = false; | ||||
| }; | ||||
| 
 | ||||
| loadData(); | ||||
| 
 | ||||
| // 搜索 | ||||
| const searchChange = (params, done) => { | ||||
|   console.log('search==', params); | ||||
|   if (done) done(); | ||||
|   state.query = params; | ||||
|   state.page.currentPage = 1; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 刷新 | ||||
| const refreshChange = () => { | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 查看 | ||||
| const rowView = (row) => { | ||||
|   crudRef.value.rowView(row); | ||||
| }; | ||||
| 
 | ||||
| // 新增 | ||||
| const rowSave = (row, done, loading) => { | ||||
|   console.log('add=', row); | ||||
| }; | ||||
| 
 | ||||
| // 编辑 | ||||
| const rowEdit = (row) => { | ||||
|   crudRef.value.rowEdit(row); | ||||
| }; | ||||
| const rowUpdate = (row, index, done, loading) => { | ||||
|   // loading.value = true; | ||||
|   console.log('update=', row); | ||||
| }; | ||||
| 
 | ||||
| // 删除 | ||||
| const rowDel = (row, index, done) => { | ||||
|   console.log('del=', row); | ||||
| }; | ||||
| </script> | ||||
| @ -1,383 +0,0 @@ | ||||
| <template> | ||||
|   <div class="custom-page"> | ||||
|     <avue-crud | ||||
|       ref="crudRef" | ||||
|       v-model="state.form" | ||||
|       v-model:search="state.query" | ||||
|       v-model:page="state.pageData" | ||||
|       :table-loading="state.loading" | ||||
|       :data="state.data" | ||||
|       :option="state.options" | ||||
|       @refresh-change="refreshChange" | ||||
|       @search-reset="searchChange" | ||||
|       @search-change="searchChange" | ||||
|       @selection-change="selectionChange" | ||||
|       @current-change="currentChange" | ||||
|       @size-change="sizeChange" | ||||
|       @row-save="rowSave" | ||||
|       @row-update="rowUpdate" | ||||
|       @row-del="rowDel" | ||||
|     > | ||||
|       <template #menu-left> | ||||
|         <el-button type="success" icon="download" @click="onExport">导出</el-button> | ||||
|       </template> | ||||
| 
 | ||||
|       <template #menu="scope"> | ||||
|         <custom-table-operate :actions="state.options.actions" :data="scope" /> | ||||
|       </template> | ||||
|     </avue-crud> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { reactive, ref } from 'vue'; | ||||
| import { useApp } from '@/hooks'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| import { isEmpty, downloadFile } from '@/utils'; | ||||
| import { useUserStore } from '@/store/modules/user'; | ||||
| import { compact } from 'lodash'; | ||||
| import { GetEntityList, AddEntity, AuditEntity, UpdateEntity, DeleteEntity, ExportEntity } from '@/apis/plan'; | ||||
| 
 | ||||
| const { VITE_APP_BASE_API } = import.meta.env; | ||||
| const app = useApp(); | ||||
| const UserStore = useUserStore(); | ||||
| const crudRef = ref(null); | ||||
| const state = reactive({ | ||||
|   loading: false, | ||||
|   query: { | ||||
|     current: 1, | ||||
|     size: 10, | ||||
|   }, | ||||
|   form: {}, | ||||
|   selection: [], | ||||
|   options: { | ||||
|     ...CRUD_OPTIONS, | ||||
|     addBtnText: '添加计划', | ||||
|     column: [ | ||||
|       { | ||||
|         label: '计划编号', | ||||
|         prop: 'id', | ||||
|         search: true, | ||||
|         addDisplay: false, | ||||
|         editDisplay: false, | ||||
|         viewDisplay: true, | ||||
|         width: 200, | ||||
|       }, | ||||
|       { | ||||
|         label: '计划名称', | ||||
|         prop: 'planName', | ||||
|         search: true, | ||||
|         width: 200, | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '种植面积(亩)', | ||||
|         prop: 'plantingArea', | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|         formatter: (row) => { | ||||
|           return row?.plantingArea ? row.plantingArea + '亩' : ''; | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '种植月份', | ||||
|         prop: 'plantingMonths', | ||||
|         type: 'select', | ||||
|         dicData: [ | ||||
|           { label: '1月', value: '1月' }, | ||||
|           { label: '2月', value: '2月' }, | ||||
|           { label: '3月', value: '3月' }, | ||||
|           { label: '4月', value: '4月' }, | ||||
|           { label: '5月', value: '5月' }, | ||||
|           { label: '6月', value: '6月' }, | ||||
|           { label: '7月', value: '7月' }, | ||||
|           { label: '8月', value: '8月' }, | ||||
|           { label: '9月', value: '9月' }, | ||||
|           { label: '10月', value: '10月' }, | ||||
|           { label: '11月', value: '11月' }, | ||||
|           { label: '12月', value: '12月' }, | ||||
|         ], | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '生长周期', | ||||
|         prop: 'growthCycle', | ||||
|         labelTip: '如:10周-12周', | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '计划进度', | ||||
|         prop: 'planProgress', | ||||
|         addDisplay: false, | ||||
|         editDisplay: false, | ||||
|         viewDisplay: true, | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '状态', | ||||
|         prop: 'planStatus', | ||||
|         type: 'select', | ||||
|         addDisplay: false, | ||||
|         editDisplay: false, | ||||
|         viewDisplay: true, | ||||
|         dicData: [ | ||||
|           { | ||||
|             label: '待提交', | ||||
|             value: 1, | ||||
|           }, | ||||
|           { | ||||
|             label: '已提交', | ||||
|             value: 2, | ||||
|           }, | ||||
|           { | ||||
|             label: '审核通过', | ||||
|             value: 3, | ||||
|           }, | ||||
|           { | ||||
|             label: '审核拒绝', | ||||
|             value: 4, | ||||
|           }, | ||||
|         ], | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '备注', | ||||
|         prop: 'note', | ||||
|         type: 'textarea', | ||||
|         span: 24, | ||||
|         rows: 4, | ||||
|         overHidden: true, | ||||
|         width: 200, | ||||
|       }, | ||||
|     ], | ||||
|     actions: [ | ||||
|       { | ||||
|         name: '查看', | ||||
|         icon: 'view', | ||||
|         event: ({ row }) => rowView(row), | ||||
|       }, | ||||
|       { | ||||
|         name: '编辑', | ||||
|         icon: 'edit', | ||||
|         event: ({ row }) => rowEdit(row), | ||||
|       }, | ||||
|       { | ||||
|         type: 'danger', | ||||
|         name: '删除', | ||||
|         icon: 'delete', | ||||
|         event: ({ row }) => rowDel(row), | ||||
|       }, | ||||
|       { | ||||
|         name: '审核通过', | ||||
|         type: 'success', | ||||
|         icon: 'check', | ||||
|         event: ({ row }) => rowCheck(row, 4), | ||||
|       }, | ||||
|       { | ||||
|         name: '审核拒绝', | ||||
|         type: 'danger', | ||||
|         icon: 'close', | ||||
|         event: ({ row }) => rowCheck(row, 3), | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   pageData: { | ||||
|     total: 0, | ||||
|     currentPage: 1, | ||||
|     pageSize: 10, | ||||
|   }, | ||||
|   data: [], | ||||
|   minWeek: null, | ||||
|   maxWeek: null, | ||||
|   currentRow: {}, | ||||
| }); | ||||
| 
 | ||||
| // 加载 | ||||
| const loadData = () => { | ||||
|   state.loading = true; | ||||
|   GetEntityList(state.query) | ||||
|     .then((res) => { | ||||
|       if (res.code === 200) { | ||||
|         const { current, size, total, records } = res.data; | ||||
|         state.data = records; | ||||
|         state.pageData = { | ||||
|           currentPage: current || 1, | ||||
|           pageSize: size || 10, | ||||
|           total: total, | ||||
|         }; | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error(err.msg); | ||||
|       state.data = []; | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       state.loading = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| loadData(); | ||||
| 
 | ||||
| // 页数 | ||||
| const currentChange = (current) => { | ||||
|   state.query.current = current; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 条数 | ||||
| const sizeChange = (size) => { | ||||
|   state.query.size = size; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 搜索 | ||||
| const searchChange = (params, done) => { | ||||
|   if (done) done(); | ||||
|   state.query = params; | ||||
|   state.query.current = 1; | ||||
|   loadData(); | ||||
| }; | ||||
| 
 | ||||
| // 刷新 | ||||
| const refreshChange = () => { | ||||
|   loadData(); | ||||
|   app.$message.success('刷新成功'); | ||||
| }; | ||||
| 
 | ||||
| // 选择 | ||||
| const selectionChange = (rows) => { | ||||
|   state.selection = rows; | ||||
| }; | ||||
| 
 | ||||
| // 查看 | ||||
| const rowView = (row) => { | ||||
|   // state.currentRow = row; | ||||
|   crudRef.value.rowView(row); | ||||
| }; | ||||
| 
 | ||||
| // 新增 | ||||
| const rowSave = (row, done, loading) => { | ||||
|   AddEntity(row) | ||||
|     .then((res) => { | ||||
|       if (res.code === 200) { | ||||
|         app.$message.success('添加成功!'); | ||||
|         done(); | ||||
|         loadData(); | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error(err.msg); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       loading(); | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 编辑 | ||||
| const rowEdit = (row) => { | ||||
|   crudRef.value.rowEdit(row); | ||||
| }; | ||||
| const rowUpdate = (row, index, done, loading) => { | ||||
|   UpdateEntity(row) | ||||
|     .then((res) => { | ||||
|       if (res.code === 200) { | ||||
|         app.$message.success('更新成功!'); | ||||
|         done(); | ||||
|         loadData(); | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error(err.msg); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       loading(); | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 删除 | ||||
| const rowDel = (row, index, done) => { | ||||
|   if (isEmpty(row)) return; | ||||
|   app | ||||
|     .$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', { | ||||
|       confirmButtonText: '确定', | ||||
|       cancelButtonText: '取消', | ||||
|       type: 'warning', | ||||
|     }) | ||||
|     .then(() => { | ||||
|       DeleteEntity({ id: row.id }) | ||||
|         .then((res) => { | ||||
|           if (res.code === 200) { | ||||
|             app.$message.success('删除成功!'); | ||||
|             done(); | ||||
|             loadData(); | ||||
|           } | ||||
|         }) | ||||
|         .catch((err) => { | ||||
|           app.$message.error(err.msg); | ||||
|         }); | ||||
|     }) | ||||
|     .catch(() => {}); | ||||
| }; | ||||
| 
 | ||||
| // 审核 | ||||
| const rowCheck = (row, status) => { | ||||
|   const data = { id: row.id, planStatus: status }; | ||||
|   AuditEntity(data) | ||||
|     .then((res) => { | ||||
|       if (res.code === 200) { | ||||
|         app.$message.success('操作成功!'); | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error(err.msg); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       loadData(); | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 导出 | ||||
| const onExport = () => { | ||||
|   if (isEmpty(state.data)) { | ||||
|     app.$message.error('当前暂时没有可供导出的数据!'); | ||||
|     return; | ||||
|   } | ||||
|   state.loading = true; | ||||
|   const fileName = '年度计划明细表'; | ||||
|   ExportEntity(state.query) | ||||
|     .then((res) => { | ||||
|       if (res.status === 200) { | ||||
|         downloadFile(res.data, `${fileName}.xlsx`, 'blob'); | ||||
|         app.$message.success('导出成功!'); | ||||
|       } | ||||
|     }) | ||||
|     .catch((err) => { | ||||
|       app.$message.error('导出失败!'); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       state.loading = false; | ||||
|     }); | ||||
| }; | ||||
| </script> | ||||
| @ -26,7 +26,7 @@ | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { reactive, ref, computed } from 'vue'; | ||||
| import { reactive, ref } from 'vue'; | ||||
| import { useApp } from '@/hooks'; | ||||
| import { sleep } from '@/utils'; | ||||
| import { CRUD_OPTIONS } from '@/config'; | ||||
| @ -36,13 +36,15 @@ const res = Mock.mock({ | ||||
|   'data|20': [ | ||||
|     { | ||||
|       id: '@increment(100000)', | ||||
|       name: '@ctitle(5,10)', | ||||
|       // name: '@ctitle(5,10)', | ||||
|       name: '一号基地', | ||||
|       'area|100-1000': 100, | ||||
|       'status|1-2': 1, | ||||
|       location: '东经 98°53′至 99°15′,北纬 23°27′至 23°40′F', | ||||
|       'type|1-2': 1, | ||||
|       'p1|1-2': 1, | ||||
|       'p2|100-1000': 100, | ||||
|       p3: '@cname(2,3)', | ||||
|       tag: '龙津河周边', | ||||
|       address: '耿马镇白塔社区', | ||||
|       createTime: '@datetime("yyyy-MM-dd HH:mm:ss")', | ||||
| @ -70,7 +72,7 @@ const state = reactive({ | ||||
|       { | ||||
|         label: '基地名称', | ||||
|         prop: 'name', | ||||
|         fixed: true, | ||||
|         // fixed: true, | ||||
|         search: true, | ||||
|         width: 200, | ||||
|         rules: { | ||||
| @ -191,6 +193,15 @@ const state = reactive({ | ||||
|           return row.area + 'm'; | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '经营主体', | ||||
|         prop: 'p3', | ||||
|         rules: { | ||||
|           required: true, | ||||
|           message: '请输入', | ||||
|           trigger: 'blur', | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         label: '创建日期', | ||||
|         prop: 'createdTime', | ||||
|  | ||||
| @ -13,6 +13,7 @@ declare module 'vue' { | ||||
|     CurrentTime: typeof import('./src/components/currentTime.vue')['default'] | ||||
|     CustomBack: typeof import('./src/components/customBack.vue')['default'] | ||||
|     CustomCard: typeof import('./src/components/CustomCard.vue')['default'] | ||||
|     CustomProgress: typeof import('./src/components/customProgress.vue')['default'] | ||||
|     CustomSelect: typeof import('./src/components/CustomSelect.vue')['default'] | ||||
|     GridSelect: typeof import('./src/components/GridSelect.vue')['default'] | ||||
|     LandClassificationType: typeof import('./src/components/LandClassificationType.vue')['default'] | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg5.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 702 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg6.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/bg9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/icon1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/icon2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/icon3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/icon4.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/plant/icon5.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/trace/bg1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								sub-government-screen-service/src/assets/images/trace/bg2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
| Before Width: | Height: | Size: 13 KiB | 
| Before Width: | Height: | Size: 4.8 KiB | 
| Before Width: | Height: | Size: 3.2 KiB | 
| Before Width: | Height: | Size: 3.6 KiB | 
| Before Width: | Height: | Size: 4.8 KiB | 
| Before Width: | Height: | Size: 4.1 KiB | 
| Before Width: | Height: | Size: 3.8 KiB | 
| Before Width: | Height: | Size: 1.9 KiB | 
| Before Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 2.3 KiB | 
| Before Width: | Height: | Size: 1.8 KiB | 
| Before Width: | Height: | Size: 2.4 KiB | 
| Before Width: | Height: | Size: 2.0 KiB | 
| Before Width: | Height: | Size: 1.6 KiB | 
| Before Width: | Height: | Size: 2.6 KiB | 
| @ -0,0 +1,67 @@ | ||||
| <template> | ||||
|   <div ref="progress" class="custom-progress-val" :style="{ background: inactiveBg }"> | ||||
|     <div class="progress-warp" :style="{ height: height }"> | ||||
|       <div class="progress" :style="{ height: height, width: pWidth + 'px', background: activateBg }"></div> | ||||
|     </div> | ||||
|     {{ width }} | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, onMounted, watch, reactive, computed } from 'vue'; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   height: { | ||||
|     type: String, | ||||
|     default: '10px', | ||||
|   }, | ||||
|   inactiveBg: { | ||||
|     type: String, | ||||
|     default: 'transparent', | ||||
|   }, | ||||
|   activateBg: { | ||||
|     type: String, | ||||
|     default: 'linear-gradient(90deg, #45bfe9 0%, #01589c 100%)', | ||||
|   }, | ||||
|   percent: { | ||||
|     type: Number, | ||||
|     default: 20, | ||||
|   }, | ||||
|   width: { | ||||
|     type: String, | ||||
|     default: null, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| let progress = ref(null); | ||||
| let maxwidth = computed(() => { | ||||
|   return progress.value && progress.value.clientWidth; | ||||
| }); | ||||
| let pWidth = computed(() => { | ||||
|   let num = 0; | ||||
|   num = Number(((maxwidth.value * props.percent) / 100).toFixed(0)); | ||||
|   return num; | ||||
| }); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .custom-progress-val { | ||||
|   width: calc(100%); | ||||
|   border-radius: 6px; | ||||
|   .progress-warp { | ||||
|     width: 100%; | ||||
|     .progress { | ||||
|       height: 100%; | ||||
|       border-radius: 6px; | ||||
|       animation: expandWidth 1s ease-in-out forwards; | ||||
|     } | ||||
| 
 | ||||
|     @keyframes expandWidth { | ||||
|       from { | ||||
|         width: 0; | ||||
|       } | ||||
|       to { | ||||
|         width: maxwidth + 'px'; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,177 @@ | ||||
| <template> | ||||
|   <div class="inventory-charts"> | ||||
|     <custom-echart-line-line :chart-data="chartsData.valData" height="100%" :option="chartsData.option" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| const legendData = reactive(['猪', '牛', '羊', '鸡', '其他']); | ||||
| let dataItem = reactive([100, 90, 200, 250, 240, 275, 120, 300, 320, 270, 290, 120]); | ||||
| let colors = reactive({ | ||||
|   猪: '#3685fe', | ||||
|   牛: '#41b879', | ||||
|   羊: '#ffd500', | ||||
|   鸡: '#e57373', | ||||
|   其他: '#46b1db', | ||||
| }); | ||||
| let colorBg = reactive({ | ||||
|   猪: [ | ||||
|     { offset: 0, color: 'rgba(54,161,255,0.6)' }, | ||||
|     { offset: 1, color: 'rgba(25,104,255,0)' }, | ||||
|   ], | ||||
|   牛: [ | ||||
|     { offset: 0, color: 'rgba(0,255,0,0.6)' }, | ||||
|     { offset: 1, color: 'rgba(25,104,255,0)' }, | ||||
|   ], | ||||
|   羊: [ | ||||
|     { offset: 0, color: 'rgba(255,213,0,0.6)' }, | ||||
|     { offset: 1, color: 'rgba(25,104,255,0)' }, | ||||
|   ], | ||||
|   鸡: [ | ||||
|     { offset: 0, color: 'rgba(299,155,155,0.6)' }, | ||||
|     { offset: 1, color: 'rgba(25,104,255,0)' }, | ||||
|   ], | ||||
|   其他: [ | ||||
|     { offset: 0, color: 'rgba(0,255,0,0.6)' }, | ||||
|     { offset: 1, color: 'rgba(70,177,219,0)' }, | ||||
|   ], | ||||
| }); | ||||
| 
 | ||||
| const currentMonth = ref(new Date().getMonth() + 1); | ||||
| const yAxisData = computed(() => { | ||||
|   let list = []; | ||||
|   for (let i = 1; i < 13; i++) { | ||||
|     let mouth = i < 10 ? i : i; | ||||
|     list.push(mouth + '月'); | ||||
|   } | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| let seriesItem = reactive({ | ||||
|   type: 'line', | ||||
|   stack: 'Total', | ||||
|   symbol: 'none', | ||||
|   smooth: true, | ||||
| }); | ||||
| 
 | ||||
| let seriesData = computed(() => { | ||||
|   let list = []; | ||||
|   if (legendData.length && legendData.length > 0) { | ||||
|     legendData.forEach((m) => { | ||||
|       let val = { | ||||
|         ...seriesItem, | ||||
|         name: m, | ||||
|         areaStyle: { | ||||
|           color: { | ||||
|             type: 'linear', | ||||
|             x: 0, | ||||
|             y: 0, | ||||
|             x2: 0, | ||||
|             y2: 1, | ||||
|             colorStops: colorBg[m], | ||||
|             global: false, // 缺省为 false | ||||
|           }, | ||||
|         }, | ||||
|         lineStyle: { | ||||
|           color: colors[m], | ||||
|           width: 1, | ||||
|           type: 'solid', | ||||
|         }, | ||||
|         data: dataItem, | ||||
|       }; | ||||
| 
 | ||||
|       list.push(val); | ||||
|     }); | ||||
|   } | ||||
|   return list; | ||||
| }); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     backgroundColor: 'transparent', | ||||
|     grid: { | ||||
|       left: '3%', | ||||
|       right: '15%', | ||||
|       bottom: '1%', | ||||
|       top: '3%', | ||||
|       containLabel: true, | ||||
|     }, | ||||
|     tooltip: { | ||||
|       trigger: 'axis', | ||||
|       axisPointer: { | ||||
|         type: 'shadow', | ||||
|       }, | ||||
|       textStyle: { | ||||
|         color: '#fff', | ||||
|         fontSize: 10, | ||||
|       }, | ||||
|       confine: true, // 超出范围 | ||||
|       backgroundColor: 'rgba(17,95,182,0.5)', //设置背景颜色 | ||||
|       formatter: function (item) { | ||||
|         let params = [...item]; | ||||
|         var res = params[0].name + '<br/>'; | ||||
|         for (var i = 0, l = params.length; i < l; i++) { | ||||
|           res += params[i].value !== '-' ? params[i].marker + params[i].seriesName + ' : ' + params[i].value + ' <br/>' : ''; | ||||
|         } | ||||
|         return res; | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: Array.from(legendData), | ||||
|       right: '0', // 距离左侧10%的位置 | ||||
|       top: 'middle', // 垂直居中 | ||||
|       orient: 'vertical', // 图例垂直排列 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     xAxis: { | ||||
|       type: 'category', | ||||
|       boundaryGap: true, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLine: { | ||||
|         lineStyle: { | ||||
|           color: '#94A7BD', //轴线和单位颜色 | ||||
|         }, | ||||
|       }, | ||||
|       data: yAxisData, | ||||
|     }, | ||||
|     yAxis: { | ||||
|       type: 'value', | ||||
|       name: ' ', | ||||
|       nameTextStyle: { | ||||
|         fontSize: 14, | ||||
|         color: '#94A7BD', | ||||
|         padding: [0, 0, 0, -45], | ||||
|       }, | ||||
|       axisLine: { | ||||
|         lineStyle: { | ||||
|           color: '#94A7BD', //轴线和单位颜色 | ||||
|         }, | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: true, | ||||
|         lineStyle: { | ||||
|           color: '#182D46', | ||||
|           type: [2, 3], | ||||
|           dashOffset: 2, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     series: seriesData.value, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .inventory-charts { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,121 @@ | ||||
| <template> | ||||
|   <div class="benefit-charts"> | ||||
|     <custom-echart-mixin :chart-data="handelData" :option="chartsData.option" height="100%" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| let itemStyle = reactive({ | ||||
|   itemStyle: { borderRadius: [8, 8, 0, 0] }, | ||||
| }); | ||||
| 
 | ||||
| let legendList = reactive(['成本', '收入', '繁殖率', '配种成功率']); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     color: ['#3685fe', '#8dcbe9', '#ffd500', '#631f9f'], | ||||
|     title: { | ||||
|       text: ' ', | ||||
|       textStyle: { | ||||
|         color: '#333', | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: legendList, | ||||
|       left: '0', // 距离左侧10%的位置 | ||||
|       top: '0', // 垂直居中 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     barStyle: { | ||||
|       barWidth: 10, | ||||
|     }, | ||||
|     dataZoom: [ | ||||
|       // { | ||||
|       //   type: 'slider', // 滑动条型数据区域缩放组件 | ||||
|       //   startValue: 0, // 数据窗口起始值的索引 | ||||
|       //   endValue: 2, // 数据窗口结束值的索引 | ||||
|       // }, | ||||
|       // { | ||||
|       //   type: 'inside', // 支持鼠标滚轮和触控板缩放和平移 | ||||
|       //   startValue: 0, | ||||
|       //   endValue: 2, | ||||
|       // }, | ||||
|     ], | ||||
|     yAxis: [ | ||||
|       { | ||||
|         type: 'value', | ||||
|         name: ' ', | ||||
|         axisLabel: { | ||||
|           formatter: '{value}', | ||||
|         }, | ||||
|         splitLine: { | ||||
|           show: true, // 显示分割线 | ||||
|           lineStyle: { | ||||
|             type: 'dashed', // 设置为虚线 | ||||
|             width: 0.5, // 分割线宽度 | ||||
|           }, | ||||
|         }, | ||||
| 
 | ||||
|         itemStyle: { fontSize: 8 }, | ||||
|       }, | ||||
|     ], | ||||
|     grid: { | ||||
|       x: '10%', | ||||
|       x2: '10%', | ||||
|       y: '20%', | ||||
|       y2: '20%', | ||||
|     }, | ||||
|   }, | ||||
|   valData: [], | ||||
| }); | ||||
| 
 | ||||
| const randomVal = (num) => { | ||||
|   let list = []; | ||||
|   for (let i = 0; i < legendList.length; i++) { | ||||
|     let addNum = [10, 8, 2, 5]; | ||||
|     let val = { | ||||
|       name: num + '月', | ||||
|       value: Number(Math.random() * 100 + addNum[i]).toFixed(2), | ||||
|       seriesType: i < legendList.length - 2 ? 'bar' : 'line', | ||||
|       type: legendList[i], | ||||
|       stack: num + '月', | ||||
|     }; | ||||
|     if (val.seriesType == 'line') { | ||||
|       val.smooth = 30; | ||||
|       val.symbol = 'none'; | ||||
|     } | ||||
|     let lastVal = { | ||||
|       ...val, | ||||
|       ...itemStyle, | ||||
|     }; | ||||
|     list[i] = i < legendList.length - 3 ? val : lastVal; | ||||
|   } | ||||
|   return list; | ||||
| }; | ||||
| let handelData = computed(() => { | ||||
|   let list = []; | ||||
|   let maxMouth = 12; | ||||
|   for (let i = 0; i < maxMouth; i++) { | ||||
|     let val = randomVal(i + 1); | ||||
|     list = [...list, ...val]; | ||||
|   } | ||||
| 
 | ||||
|   list.map((m, indexm) => { | ||||
|     return { ...m, value: Number(Number(m.value) + Math.random() + indexm).toFixed(0) }; | ||||
|   }); | ||||
|   // console.info('handelData', list); | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .benefit-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,161 @@ | ||||
| <template> | ||||
|   <div class="demo device-charts" 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="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 }"> | ||||
|             <template v-for="(b, indexb) in listKeys" :key="indexb"> | ||||
|               <div class="item-td" :class="item.status == 1 ? 'td-title' : 'td-warn'" :style="{ width: 'calc(100% / ' + listKeys.length + ')' }"> | ||||
|                 <span v-if="b == 'num'"> | ||||
|                   {{ item[b] }} | ||||
|                 </span> | ||||
|                 <span v-else-if="b == 'duration'" class="duration"> | ||||
|                   <span class="val">{{ item[b] + 'h' }}</span> | ||||
|                   <div class="pro"> | ||||
|                     <customProgress height="5px" :percent="item.percent" inactive-bg="#081931"></customProgress> | ||||
|                   </div> | ||||
|                 </span> | ||||
|                 <span v-else> | ||||
|                   {{ item[b] == 0 ? '待机' : '运行' }} | ||||
|                 </span> | ||||
|               </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'; | ||||
| import customProgress from '@/components/customProgress.vue'; | ||||
| const props = defineProps({ | ||||
|   //   items: { | ||||
|   //     type: Array, | ||||
|   //     default: () => [], | ||||
|   //   }, | ||||
| }); | ||||
| 
 | ||||
| let list = reactive([ | ||||
|   { num: '投喂机', duration: '3.7', status: 1 }, | ||||
|   { num: '喂水机', duration: '10.0', status: 1 }, | ||||
|   { num: '投喂机', duration: '6.4', status: 1 }, | ||||
|   { num: '喂水机', duration: '3.9', status: 1 }, | ||||
|   { num: '投喂机', duration: '3.6', status: 0 }, | ||||
|   { num: '喂水机', duration: '4.5', status: 1 }, | ||||
|   { num: '投喂机', duration: '5.6', status: 1 }, | ||||
| ]); | ||||
| 
 | ||||
| const listKeys = reactive(['num', 'status', 'duration']); | ||||
| const listKeysHeader = reactive({ | ||||
|   num: '设备编号', | ||||
|   status: '设备状态', | ||||
|   duration: '设备今日运行时长', | ||||
| }); | ||||
| 
 | ||||
| let datalist = computed(() => { | ||||
|   return list.map((m) => { | ||||
|     return { | ||||
|       ...m, | ||||
|       percent: Number((Number(parseInt(m.duration) / max.value) * 100).toFixed(0)), | ||||
|     }; | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| let max = computed(() => { | ||||
|   let valueList = new Set(list.map((item) => item.duration)); | ||||
|   let sortValue = [...valueList].sort((a, b) => b - a) || []; | ||||
|   // console.info('valueList', sortValue); | ||||
|   return sortValue.length ? sortValue[0] : 0; | ||||
| }); | ||||
| 
 | ||||
| const classOptions = { | ||||
|   singleHeight: 48, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style scoped lang="scss"> | ||||
| .device-charts { | ||||
|   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; | ||||
|       } | ||||
| 
 | ||||
|       &.td-warn { | ||||
|         color: red !important; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .item-warp { | ||||
|     display: inline-flex; | ||||
|     justify-content: space-around; | ||||
|     .item-td { | ||||
|       display: inline-block; | ||||
|       vertical-align: middle; | ||||
| 
 | ||||
|       text-align: center; | ||||
|       color: #fff; | ||||
|     } | ||||
|     .duration { | ||||
|       width: 100%; | ||||
|       .val, | ||||
|       .pro { | ||||
|         display: inline-block; | ||||
|         vertical-align: middle; | ||||
|         box-sizing: border-box; | ||||
|       } | ||||
|       .val { | ||||
|         width: 50px; | ||||
|         padding-right: 10px; | ||||
|       } | ||||
|       .pro { | ||||
|         width: calc(100% - 50px); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .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> | ||||
| @ -0,0 +1,174 @@ | ||||
| <template> | ||||
|   <div class="plant-environment-warp"> | ||||
|     <div class="data-item-row"> | ||||
|       <div | ||||
|         v-for="(n, index) in datalist" | ||||
|         :key="index" | ||||
|         :style="{ | ||||
|           'background-image': 'url(' + getAssetsFile('images/plant/bg3.png') + ')', | ||||
|           width: 'calc((100% - 30px) /' + datalist.length + ')', | ||||
|         }" | ||||
|         class="data-item" | ||||
|       > | ||||
|         <div class="data-warp"> | ||||
|           <div class="data-pos"> | ||||
|             <div class="data-pos-center"> | ||||
|               <div class="pos-center"> | ||||
|                 <span class="label">{{ n.label }}</span> | ||||
|                 <div class="value"> | ||||
|                   <span>{{ n.value }}</span> | ||||
|                   <span class="unit">{{ n.unit }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="small-bg"> | ||||
|             <img :src="getAssetsFile('images/plant/bg6.png')" /> | ||||
|             <img :src="getAssetsFile('images/plant/' + n.icon)" class="img-icon" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| import { ref, reactive, onMounted, watch } from 'vue'; | ||||
| import { useRouter } from 'vue-router'; | ||||
| import { useApp } from '@/hooks'; | ||||
| 
 | ||||
| const router = useRouter(); | ||||
| const props = defineProps({ | ||||
|   title: { | ||||
|     type: String, | ||||
|     default: '统计分析', | ||||
|   }, | ||||
|   postion: { | ||||
|     type: String, | ||||
|     default: 'left', | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| let topTitle = ref(''); | ||||
| let pos = ref(''); | ||||
| 
 | ||||
| const datalist = reactive([ | ||||
|   { label: '空气温度', value: 28.6, unit: '℃', icon: 'icon4.png' }, | ||||
|   { label: '空气湿度', value: 30, unit: '%', icon: 'icon3.png' }, | ||||
|   { label: '光照强度', value: 1000, unit: 'lux', icon: 'icon1.png' }, | ||||
|   { label: '降水量', value: 100, unit: 'mm', icon: 'icon2.png' }, | ||||
| ]); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   if (datalist.length) { | ||||
|     datalist.forEach((m, index) => { | ||||
|       let num = 0; | ||||
|       switch (index) { | ||||
|         case 0: | ||||
|           num = 20; | ||||
|           break; | ||||
|         case 1: | ||||
|           num = 30; | ||||
|           break; | ||||
|         case 2: | ||||
|           num = 1000; | ||||
|           break; | ||||
|         case 3: | ||||
|           num = 100; | ||||
|           break; | ||||
|         default: | ||||
|           num = 10; | ||||
|           break; | ||||
|       } | ||||
| 
 | ||||
|       m.value = (Math.random() + num).toFixed(2); | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => (props.title, props.postion), | ||||
|   () => { | ||||
|     topTitle.value = props.title; | ||||
|     pos.value = props.postion; | ||||
|   }, | ||||
|   { | ||||
|     deep: true, | ||||
|     immediate: true, | ||||
|   } | ||||
| ); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .plant-environment-warp { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   .data-item-row { | ||||
|     height: 100%; | ||||
|     width: 100%; | ||||
|     display: inline-flex; | ||||
|     justify-content: space-around; | ||||
|     flex-wrap: wrap; | ||||
|     gap: 10px; | ||||
|   } | ||||
|   .data-item { | ||||
|     height: 100%; | ||||
|     background-size: 100% 100%; | ||||
|     position: relative; | ||||
|   } | ||||
|   .data-warp { | ||||
|     padding: 8px 0; | ||||
|     text-align: center; | ||||
|     z-index: 1; | ||||
|     display: inline-flex; | ||||
|     justify-content: center; | ||||
|     .small-bg, | ||||
|     .data-pos { | ||||
|       display: inline-flex; | ||||
|       vertical-align: middle; | ||||
|       .data-pos-center { | ||||
|         display: inline-flex; | ||||
|         justify-content: space-around; | ||||
|         flex-direction: column; | ||||
|         height: 100%; | ||||
|         .pos-center { | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     .small-bg { | ||||
|       width: 38px; | ||||
|       height: 38px; | ||||
|       position: relative; | ||||
|       margin-top: 10%; | ||||
|       .img-icon { | ||||
|         position: absolute; | ||||
|         left: 50%; | ||||
|         top: 50%; | ||||
|         transform: translate(-50%, -50%); | ||||
|         width: 38%; | ||||
|         height: 38%; | ||||
|       } | ||||
|     } | ||||
|     .data-pos { | ||||
|       width: calc(100% - 54px); | ||||
|       .label, | ||||
|       .value { | ||||
|         display: inline-block; | ||||
|         width: 100%; | ||||
|       } | ||||
|       .label { | ||||
|         color: #fff; | ||||
|         font-size: 13px; | ||||
|       } | ||||
|       .value { | ||||
|         color: #6beff9; | ||||
|         font-size: 16px; | ||||
|         font-weight: bold; | ||||
|         margin-top: 6px; | ||||
|       } | ||||
|       .unit { | ||||
|         font-size: 10px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,117 @@ | ||||
| <template> | ||||
|   <div class="growth-indexes-charts"> | ||||
|     <custom-echart-mixin :chart-data="handelData" :option="chartsData.option" height="100%" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| let itemStyle = reactive({ | ||||
|   itemStyle: { borderRadius: [8, 8, 0, 0] }, | ||||
| }); | ||||
| 
 | ||||
| let legendList = reactive(['猪', '牛', '羊', '鸡', '其他']); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     color: ['#3685fe', '#41b879', '#ffd500', '#e57373'], | ||||
|     title: { | ||||
|       text: ' ', | ||||
|       textStyle: { | ||||
|         color: '#333', | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: legendList, | ||||
|       left: '0', // 距离左侧10%的位置 | ||||
|       top: '0', // 垂直居中 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     barStyle: { | ||||
|       barWidth: 10, | ||||
|     }, | ||||
|     dataZoom: [ | ||||
|       // { | ||||
|       //   type: 'slider', // 滑动条型数据区域缩放组件 | ||||
|       //   startValue: 0, // 数据窗口起始值的索引 | ||||
|       //   endValue: 2, // 数据窗口结束值的索引 | ||||
|       // }, | ||||
|       // { | ||||
|       //   type: 'inside', // 支持鼠标滚轮和触控板缩放和平移 | ||||
|       //   startValue: 0, | ||||
|       //   endValue: 2, | ||||
|       // }, | ||||
|     ], | ||||
|     yAxis: [ | ||||
|       { | ||||
|         type: 'value', | ||||
|         name: ' ', | ||||
|         axisLabel: { | ||||
|           formatter: '{value}', | ||||
|         }, | ||||
|         splitLine: { | ||||
|           show: true, // 显示分割线 | ||||
|           lineStyle: { | ||||
|             type: 'dashed', // 设置为虚线 | ||||
|             width: 0.5, // 分割线宽度 | ||||
|           }, | ||||
|         }, | ||||
| 
 | ||||
|         itemStyle: { fontSize: 8 }, | ||||
|       }, | ||||
|     ], | ||||
|     grid: { | ||||
|       x: '10%', | ||||
|       x2: '10%', | ||||
|       y: '20%', | ||||
|       y2: '20%', | ||||
|     }, | ||||
|   }, | ||||
|   valData: [], | ||||
| }); | ||||
| 
 | ||||
| const randomVal = (num) => { | ||||
|   let list = []; | ||||
|   for (let i = 0; i < legendList.length; i++) { | ||||
|     let addNum = [10, 8, 2, 5]; | ||||
|     let val = { | ||||
|       name: num + '月', | ||||
|       value: Number(Math.random() * 100 + addNum[i]).toFixed(2), | ||||
|       seriesType: 'bar', | ||||
|       type: legendList[i], | ||||
|       stack: num + '月', | ||||
|     }; | ||||
|     let lastVal = { | ||||
|       ...val, | ||||
|       ...itemStyle, | ||||
|     }; | ||||
|     list[i] = i < legendList.length - 1 ? val : lastVal; | ||||
|   } | ||||
|   return list; | ||||
| }; | ||||
| let handelData = computed(() => { | ||||
|   let list = []; | ||||
|   let maxMouth = 12; | ||||
|   for (let i = 0; i < maxMouth; i++) { | ||||
|     let val = randomVal(i + 1); | ||||
|     list = [...list, ...val]; | ||||
|   } | ||||
| 
 | ||||
|   list.map((m, indexm) => { | ||||
|     return { ...m, value: Number(Number(m.value) + Math.random() + indexm).toFixed(0) }; | ||||
|   }); | ||||
|   // console.info('handelData', list); | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .growth-indexes-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,122 @@ | ||||
| <template> | ||||
|   <div class="demo health-status-charts" 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="item.status == 1 ? 'td-title' : 'td-warn'" :style="{ width: 'calc(100% / ' + listKeys.length + ')' }"> | ||||
|                 <span v-if="b != 'status'"> | ||||
|                   {{ item[b] }} | ||||
|                 </span> | ||||
|                 <el-icon v-else> | ||||
|                   <Bell></Bell> | ||||
|                 </el-icon> | ||||
|               </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([ | ||||
|   { diseaseType: '瘟疫', incidenceRate: '23%', coverage: '84%', status: 1 }, | ||||
|   { diseaseType: '蓝耳病', incidenceRate: '19%', coverage: '88%', status: 1 }, | ||||
|   { diseaseType: '口蹄疫', incidenceRate: '45%', coverage: '68%', status: 1 }, | ||||
|   { diseaseType: '链球病菌', incidenceRate: '35%', coverage: '88%', status: 1 }, | ||||
|   { diseaseType: '炎症', incidenceRate: '8%', coverage: '98%', status: 1 }, | ||||
|   { diseaseType: '寄生虫', incidenceRate: '11%', coverage: '99%', status: 1 }, | ||||
| ]); | ||||
| 
 | ||||
| const listKeys = reactive(['diseaseType', 'incidenceRate', 'coverage', 'status']); | ||||
| const listKeysHeader = reactive({ | ||||
|   diseaseType: '疾病种类', | ||||
|   incidenceRate: '发病率', | ||||
|   coverage: '疫苗接种率', | ||||
|   status: '预警', | ||||
| }); | ||||
| 
 | ||||
| const classOptions = { | ||||
|   singleHeight: 48, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style scoped lang="scss"> | ||||
| .health-status-charts { | ||||
|   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; | ||||
|       } | ||||
| 
 | ||||
|       &.td-warn { | ||||
|         color: red !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> | ||||
| @ -0,0 +1,179 @@ | ||||
| <template> | ||||
|   <div class="irrigation-charts"> | ||||
|     <div class="charts-content"> | ||||
|       <div class="water-droplet-bg" :style="{ 'background-image': 'url(' + getAssetsFile('images/plant/bg5.png') + ')' }"> | ||||
|         <div class="water-droplet"> | ||||
|           <custom-echart-water-droplet height="100%" :option="option" /> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="water-droplet-warp"> | ||||
|         <template v-for="(n, index) in itemlist" :key="index"> | ||||
|           <div class="water-droplet-item" :style="{ height: 'calc((100% - 20px) / ' + itemlist.length + ')' }"> | ||||
|             <div class="title" :style="{ 'background-image': 'url(' + getAssetsFile(n.bg1) + ')' }"> | ||||
|               <div class="title-val" :style="{ color: n.color }">{{ n.title }}</div> | ||||
|             </div> | ||||
|             <div class="tips" :style="{ 'background-image': 'url(' + getAssetsFile(n.bg2) + ')' }"> | ||||
|               <span class="tips-val">{{ n.tips }}</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </template> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| let percent = ref(0.6); | ||||
| let itemlist = reactive([ | ||||
|   { title: '智能喂水', bg1: 'images/plant/bg8.png', bg2: 'images/plant/bg7.png', tips: '去喂水', color: '#4a90e2ff' }, | ||||
|   { title: '智能投喂', bg1: 'images/plant/bg9.png', bg2: 'images/plant/bg7.png', tips: '去投喂', color: '#50e3c2ff' }, | ||||
| ]); | ||||
| const option = reactive({ | ||||
|   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 | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .irrigation-charts { | ||||
|   height: 100%; | ||||
|   .charts-content { | ||||
|     display: inline-flex; | ||||
|     justify-content: space-between; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     .water-droplet-bg { | ||||
|       display: inline-block; | ||||
|       width: 40%; | ||||
|       background-size: contain; | ||||
|       background-repeat: no-repeat; | ||||
|       background-position: center bottom; | ||||
|       position: relative; | ||||
|       .water-droplet { | ||||
|         position: absolute; | ||||
|         left: 50%; | ||||
|         top: 10%; | ||||
|         transform: translateX(-50%); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     .water-droplet-warp { | ||||
|       width: 60%; | ||||
|       padding: 0 10px; | ||||
|       display: inline-flex; | ||||
|       vertical-align: middle; | ||||
|       flex-direction: column; | ||||
|       .water-droplet-item { | ||||
|         width: 100%; | ||||
|       } | ||||
|       .title, | ||||
|       .tips { | ||||
|         display: inline-block; | ||||
|         color: #fff; | ||||
|         vertical-align: top; | ||||
|         .tips-val { | ||||
|           display: inline-flex; | ||||
|           line-height: 42px; | ||||
|           text-align: center; | ||||
|           font-size: 14px; | ||||
|           font-weight: bold; | ||||
|           transform: skewX(-13deg) translateY(-50%); | ||||
|           background: linear-gradient(to bottom, '#ff7e5f', '#548fff'); | ||||
|           -webkit-background-clip: text; | ||||
|           color: #fff; | ||||
|           letter-spacing: 2px; | ||||
|           text-shadow: -6px 0 0 1px #add8f1; | ||||
|           position: absolute; | ||||
|           left: 0; | ||||
|           top: 50%; | ||||
|         } | ||||
|       } | ||||
|       .title { | ||||
|         width: 40%; | ||||
|         height: 100%; | ||||
|         background-size: contain; | ||||
|         background-position: left bottom; | ||||
|         background-repeat: no-repeat; | ||||
|         .title-val { | ||||
|           width: 100%; | ||||
|           text-align: center; | ||||
|           line-height: 32px; | ||||
|         } | ||||
|       } | ||||
|       .tips { | ||||
|         width: 60%; | ||||
|         height: 100%; | ||||
|         background-size: 100% auto; | ||||
|         background-repeat: no-repeat; | ||||
|         background-position: left center; | ||||
|         position: relative; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,25 @@ | ||||
| <template> | ||||
|   <div class="monitoring-screen-warp"> | ||||
|     <div class="monitoring-screen-content" :style="{ 'background-image': 'url(' + getAssetsFile('images/plant/bg2.png') + ')' }"></div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .monitoring-screen-warp { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   box-sizing: border-box; | ||||
|   .monitoring-screen-content { | ||||
|     background-size: 100% 100%; | ||||
|     background-repeat: no-repeat; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     padding: 10px 0; | ||||
|     div { | ||||
|       box-sizing: border-box; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,73 @@ | ||||
| <template> | ||||
|   <div class="notice-bar-warp" :style="{ height: height }"> | ||||
|     <div class="notice-bar-pos"> | ||||
|       <div class="notice-icon"> | ||||
|         <img :src="getAssetsFile('images/plant/icon5.png')" /> | ||||
|       </div> | ||||
|       <div class="notice-bar" :style="{ 'line-height': height }"> | ||||
|         <div class="scrolling-text"> | ||||
|           <span>{{ text }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| defineProps({ | ||||
|   text: { | ||||
|     type: String, | ||||
|     required: true, | ||||
|     default: '这是一条滚动通知消息,请注意查看!', | ||||
|   }, | ||||
|   height: { | ||||
|     type: String || Number, | ||||
|     default: '40px', | ||||
|   }, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style scoped lang="scss"> | ||||
| .notice-bar-warp { | ||||
|   width: 100%; | ||||
|   display: inline-flex; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   .notice-bar-pos { | ||||
|     display: inline-flex; | ||||
|     width: 100%; | ||||
|   } | ||||
|   .notice-icon { | ||||
|     display: inline-block; | ||||
|     vertical-align: middle; | ||||
|     width: 30px; | ||||
|     img { | ||||
|       width: 80%; | ||||
|       height: 80%; | ||||
|       margin: 10% 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| .notice-bar { | ||||
|   display: inline-block; | ||||
|   overflow: hidden; | ||||
|   width: calc(100% - 30px); | ||||
| } | ||||
| 
 | ||||
| .scrolling-text { | ||||
|   white-space: nowrap; | ||||
|   animation: scroll-left 10s linear infinite; | ||||
|   color: #fff; | ||||
| } | ||||
| 
 | ||||
| @keyframes scroll-left { | ||||
|   0% { | ||||
|     transform: translateX(100%); | ||||
|   } | ||||
|   100% { | ||||
|     transform: translateX(-100%); | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,22 @@ | ||||
| <template> | ||||
|   <div class="plant-gs-warp"> | ||||
|     <div class="plant-gs-content" :style="{ 'background-image': 'url(' + getAssetsFile('images/plant/bg1.png') + ')' }"></div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .plant-gs-warp { | ||||
|   height: 100%; | ||||
|   padding: 10px 0; | ||||
|   width: 100%; | ||||
|   box-sizing: border-box; | ||||
|   .plant-gs-content { | ||||
|     background-size: 100% 100%; | ||||
|     background-repeat: no-repeat; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,113 @@ | ||||
| <template> | ||||
|   <div class="water-intake-charts"> | ||||
|     <custom-echart-mixin :chart-data="handelData" :option="chartsData.option" height="100%" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| let itemStyle = reactive({ | ||||
|   itemStyle: { borderRadius: [8, 8, 0, 0] }, | ||||
| }); | ||||
| 
 | ||||
| let legendList = reactive(['饮水量', '饲料量']); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     color: ['#3685fe', '#41b879', '#ffd500', '#e57373'], | ||||
|     title: { | ||||
|       text: ' ', | ||||
|       textStyle: { | ||||
|         color: '#333', | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: legendList, | ||||
|       left: '0', // 距离左侧10%的位置 | ||||
|       top: '0', // 垂直居中 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     barStyle: { | ||||
|       barWidth: 10, | ||||
|     }, | ||||
|     dataZoom: [ | ||||
|       { | ||||
|         type: 'slider', // 滑动条型数据区域缩放组件 | ||||
|         startValue: 0, // 数据窗口起始值的索引 | ||||
|         endValue: 5, // 数据窗口结束值的索引 | ||||
|       }, | ||||
|       { | ||||
|         type: 'inside', // 支持鼠标滚轮和触控板缩放和平移 | ||||
|         startValue: 0, | ||||
|         endValue: 5, | ||||
|       }, | ||||
|     ], | ||||
|     yAxis: [ | ||||
|       { | ||||
|         type: 'value', | ||||
|         name: ' ', | ||||
|         axisLabel: { | ||||
|           formatter: '{value}', | ||||
|         }, | ||||
|         splitLine: { | ||||
|           show: true, // 显示分割线 | ||||
|           lineStyle: { | ||||
|             type: 'dashed', // 设置为虚线 | ||||
|             width: 0.5, // 分割线宽度 | ||||
|           }, | ||||
|         }, | ||||
| 
 | ||||
|         itemStyle: { fontSize: 8 }, | ||||
|       }, | ||||
|     ], | ||||
|     grid: { | ||||
|       x: '10%', | ||||
|       x2: '15%', | ||||
|       y: '20%', | ||||
|       y2: '20%', | ||||
|     }, | ||||
|   }, | ||||
|   valData: [], | ||||
| }); | ||||
| 
 | ||||
| const randomVal = (num) => { | ||||
|   let list = []; | ||||
|   for (let i = 0; i < legendList.length; i++) { | ||||
|     let addNum = [10, 8, 2, 5]; | ||||
|     let val = { | ||||
|       name: num + '月', | ||||
|       value: Number(Math.random() * 100 + addNum[i]).toFixed(2), | ||||
|       seriesType: 'bar', | ||||
|       type: legendList[i], | ||||
|       ...itemStyle, | ||||
|     }; | ||||
|     list[i] = val; | ||||
|   } | ||||
|   return list; | ||||
| }; | ||||
| let handelData = computed(() => { | ||||
|   let list = []; | ||||
|   let maxMouth = 12; | ||||
|   for (let i = 0; i < maxMouth; i++) { | ||||
|     let val = randomVal(i + 1); | ||||
|     list = [...list, ...val]; | ||||
|   } | ||||
| 
 | ||||
|   list.map((m) => { | ||||
|     return { ...m, value: Number(m.value + Math.random() + 10).toFixed(2) }; | ||||
|   }); | ||||
|   // console.info('handelData', list); | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .water-intake-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -4,15 +4,81 @@ | ||||
|       <template #center> | ||||
|         <el-row style="width: 100%; height: 100%"> | ||||
|           <el-col :span="6" class="left-charts"> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="存栏数据分析" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <InventoryCharts></InventoryCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="饲料与饮水量监测" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <waterIntakeCharts></waterIntakeCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="生长指标监测" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <growthIndexesCharts></growthIndexesCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <el-row style="height: 67%"> | ||||
|               <el-col :span="24" class="center-top"> | ||||
|                 <div class="notice"> | ||||
|                   <noticeBar :height="'40px'"></noticeBar> | ||||
|                 </div> | ||||
|                 <div class="top"> | ||||
|                   <environment></environment> | ||||
|                 </div> | ||||
|                 <div class="map-gis"> | ||||
|                   <plantgs></plantgs> | ||||
|                 </div> | ||||
|               </el-col> | ||||
|             </el-row> | ||||
|             <el-row style="height: 33%" :gutter="30"> | ||||
|               <el-col :span="12" style="height: 100%"> | ||||
|                 <customBack top-title="健康状况指标" :top-postion="'left'"> | ||||
|                   <template #back> | ||||
|                     <healthStatusCharts></healthStatusCharts> | ||||
|                   </template> | ||||
|                 </customBack> | ||||
|               </el-col> | ||||
|               <el-col :span="12" style="height: 100%"> | ||||
|                 <customBack top-title="智慧投喂控制" :top-postion="'right'"> | ||||
|                   <template #back> | ||||
|                     <irrigationCharts></irrigationCharts> | ||||
|                   </template> | ||||
|                 </customBack> | ||||
|               </el-col> | ||||
|             </el-row> | ||||
|           </el-col> | ||||
|           <el-col :span="12"></el-col> | ||||
|           <el-col :span="6" class="right-charts"> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="智慧监控" :top-postion="'right'"> | ||||
|                 <template #back> | ||||
|                   <monitoringScreen></monitoringScreen> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="生产性能与效益数额" :top-postion="'right'"> | ||||
|                 <template #back> | ||||
|                   <benefitCharts></benefitCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="设备数据统计" :top-postion="'right'"> | ||||
|                 <template #back> | ||||
|                   <deviceCharts></deviceCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
|         </el-row> | ||||
|       </template> | ||||
| @ -21,6 +87,18 @@ | ||||
| </template> | ||||
| <script setup> | ||||
| import baseBg from '@/components/baseBg.vue'; | ||||
| import customBack from '@/components/customBack.vue'; | ||||
| import InventoryCharts from './components/InventoryCharts.vue'; | ||||
| import waterIntakeCharts from './components/waterIntakeCharts.vue'; | ||||
| import growthIndexesCharts from './components/growthIndexesCharts.vue'; | ||||
| import environment from './components/environment.vue'; | ||||
| import plantgs from './components/plantgs.vue'; | ||||
| import noticeBar from './components/noticeBar.vue'; | ||||
| import irrigationCharts from './components/irrigationCharts.vue'; | ||||
| import healthStatusCharts from './components/healthStatusCharts.vue'; | ||||
| import monitoringScreen from './components/monitoringScreen.vue'; | ||||
| import benefitCharts from './components/benefitCharts.vue'; | ||||
| import deviceCharts from './components/deviceCharts.vue'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .data-home-index { | ||||
| @ -33,6 +111,7 @@ import baseBg from '@/components/baseBg.vue'; | ||||
|   } | ||||
|   .left-charts-item { | ||||
|     width: 100%; | ||||
|     height: calc((100% - 30px) / 3); | ||||
|   } | ||||
| 
 | ||||
|   .right-charts { | ||||
| @ -46,5 +125,24 @@ import baseBg from '@/components/baseBg.vue'; | ||||
|     width: 100%; | ||||
|     height: calc((100% - 30px) / 3); | ||||
|   } | ||||
| 
 | ||||
|   .center-top { | ||||
|     padding: 16px; | ||||
|     .notice, | ||||
|     .top, | ||||
|     .map-gis { | ||||
|       display: inline-block; | ||||
|       width: 100%; | ||||
|     } | ||||
|     .notice { | ||||
|       height: 40px; | ||||
|     } | ||||
|     .top { | ||||
|       height: 80px; | ||||
|     } | ||||
|     .map-gis { | ||||
|       height: calc(100% - 140px); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -0,0 +1,125 @@ | ||||
| <template> | ||||
|   <div class="demo back-to-roll-list" 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 + ')' }"> | ||||
|                 <span> | ||||
|                   {{ item[b] }} | ||||
|                 </span> | ||||
|               </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: '农业管理局', time: '2025.01.02', info: '2025农业规划' }, | ||||
|   { title: '农业管理局', time: '2025.01.01', info: '2025养殖规划' }, | ||||
|   { title: '农业管理局', time: '2025.01.02', info: '2025种植规划' }, | ||||
|   { title: '农业管理局', time: '2025.01.01', info: '2025最新政策解读' }, | ||||
|   { title: '农业管理局', time: '2025.01.02', info: '2025最新农业政策' }, | ||||
|   { title: '农业管理局', time: '2025.01.01', info: '2025最新养殖政策' }, | ||||
|   { title: '农业管理局', time: '2025.01.02', info: '2025最新种植政策' }, | ||||
| ]); | ||||
| 
 | ||||
| const listKeys = reactive(['title', 'info', 'time']); | ||||
| const listKeysHeader = reactive({ | ||||
|   title: '发布单位', | ||||
|   info: '热点信息', | ||||
|   time: '发布时间', | ||||
| }); | ||||
| 
 | ||||
| const classOptions = { | ||||
|   singleHeight: 48, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style scoped lang="scss"> | ||||
| .back-to-roll-list { | ||||
|   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: 6px 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; | ||||
| 
 | ||||
|       .status-no { | ||||
|         color: red; | ||||
|       } | ||||
|       .status-y { | ||||
|         color: #6beff9; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .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> | ||||
| @ -0,0 +1,91 @@ | ||||
| <template> | ||||
|   <div class="product-type-word-clould"> | ||||
|     <custom-echart-word-cloud :chart-data="chartsData.valData" height="100%" :option="chartsData.option" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| 
 | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     backgroundColor: 'transparent', | ||||
|     tooltip: { | ||||
|       show: true, | ||||
|       textStyle: { | ||||
|         fontSize: '16', | ||||
|         color: '#3c3c3c', | ||||
|       }, | ||||
|       backgroundColor: '#fff', | ||||
|       borderColor: '#ddd', | ||||
|       borderWidth: 1, | ||||
|     }, | ||||
|     series: [], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { | ||||
|       type: 'wordCloud', | ||||
|       // 网格大小,各项之间间距 | ||||
|       gridSize: 30, | ||||
|       // 形状 circle 圆,cardioid  心, diamond 菱形, | ||||
|       // triangle-forward 、triangle 三角,star五角星 | ||||
|       shape: 'circle', | ||||
|       // 字体大小范围 | ||||
|       sizeRange: [10, 30], | ||||
|       // 文字旋转角度范围 | ||||
|       rotationRange: [0, 0], | ||||
|       // 旋转步值 | ||||
|       rotationStep: 90, | ||||
|       // 自定义图形 | ||||
|       // maskImage: maskImage, | ||||
|       left: 'center', | ||||
|       top: 'center', | ||||
|       right: null, | ||||
|       bottom: null, | ||||
|       // 画布宽 | ||||
|       width: '100%', | ||||
|       // 画布高 | ||||
|       height: '100%', | ||||
|       // 是否渲染超出画布的文字 | ||||
|       drawOutOfBound: false, | ||||
|       textStyle: { | ||||
|         color: function () { | ||||
|           const colors = ['#165DFF', '#6aca37', '#05a4b6', '#f93920', '#f0b114']; | ||||
|           return colors[parseInt(Math.random() * colors.length)]; | ||||
|         }, | ||||
|         emphasis: { | ||||
|           shadowBlur: 10, | ||||
|           shadowColor: '#2ac', | ||||
|         }, | ||||
|       }, | ||||
|       data: [ | ||||
|         { value: 11.7392043070835, name: '有机白菜' }, | ||||
|         { value: 9.23723855786, name: '土鸡蛋' }, | ||||
|         { value: 7.75434839431, name: '猪肉' }, | ||||
|         { value: 11.3865516372, name: '牛肉' }, | ||||
|         { value: 7.75434839431, name: '零添加' }, | ||||
|         { value: 5.83541244308, name: '原产地' }, | ||||
|         { value: 15.83541244308, name: '菠萝' }, | ||||
|         { value: 2.83541244308, name: '甘蔗' }, | ||||
|         { value: 5.83541244308, name: '土豆' }, | ||||
|         { value: 10.83541244308, name: '绿色' }, | ||||
|         { value: 5.83541244308, name: '美味' }, | ||||
|         { value: 5.83541244308, 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> | ||||
| .product-type-word-clould { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -4,15 +4,35 @@ | ||||
|       <template #center> | ||||
|         <el-row style="width: 100%; height: 100%"> | ||||
|           <el-col :span="6" class="left-charts"> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="舆情数据统计" :top-postion="'left'"> | ||||
|                 <template #back> </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="追溯主体统计" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <backToCharts></backToCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="追溯产品分类" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <productTypeWordClould></productTypeWordClould> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <centerMap></centerMap> | ||||
|           </el-col> | ||||
|           <el-col :span="12"></el-col> | ||||
|           <el-col :span="6" class="right-charts"> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item" style="height: 100%"> | ||||
|               <customBack top-title="农场品实时价格" :top-postion="'right'"> | ||||
|                 <template #back> </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
|         </el-row> | ||||
|       </template> | ||||
| @ -21,6 +41,10 @@ | ||||
| </template> | ||||
| <script setup> | ||||
| import baseBg from '@/components/baseBg.vue'; | ||||
| import customBack from '@/components/customBack.vue'; | ||||
| import centerMap from '@/components/centerMap.vue'; | ||||
| import backToCharts from './components/backToCharts.vue'; | ||||
| import productTypeWordClould from './components/productTypeWordClould.vue'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .data-home-index { | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <template> | ||||
|   <div class="demo roll-list" style="height: 100%" ref="refroll"> | ||||
|     <vue3ScrollSeamless class="scroll-wrap" :classOptions="classOptions" :dataList="datalist"> | ||||
|   <div ref="refroll" class="demo roll-list" style="height: 100%"> | ||||
|     <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-l"> | ||||
| @ -8,11 +8,7 @@ | ||||
|               <span class="label"> {{ item.title || '--' }}</span> | ||||
|               <span class="value"> {{ item.value || '0' }}</span> | ||||
|             </div> | ||||
|             <div class="progress-val"> | ||||
|               <div class="progress-warp" :style="{ width: item.percent + 'px' }"> | ||||
|                 <div class="progress"></div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <customProgress height="6px" :percent="item.percent" inactive-bg="#081931"></customProgress> | ||||
|           </div> | ||||
|           <div class="list-item-r"> | ||||
|             {{ '0' + (index + 1) }} | ||||
| @ -27,6 +23,7 @@ | ||||
| <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, | ||||
| @ -44,7 +41,11 @@ const classOptions = { | ||||
| let datalist = computed(() => { | ||||
|   let maxwidth = refroll.value && refroll.value.clientWidth; | ||||
|   return list.map((m) => { | ||||
|     return { ...m, percent: parseInt(Number(parseInt(m.value) / max.value) * maxwidth) }; | ||||
|     //return { ...m, percent: parseInt(Number(parseInt(m.value) / max.value) * maxwidth) }; | ||||
|     return { | ||||
|       ...m, | ||||
|       percent: Number((Number(parseInt(m.value) / max.value) * 100).toFixed(0)), | ||||
|     }; | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| @ -105,26 +106,6 @@ let max = computed(() => { | ||||
|         right: 0; | ||||
|         bottom: 0; | ||||
|       } | ||||
|       .progress-val { | ||||
|         width: calc(100%); | ||||
|         .progress-warp { | ||||
|           .progress { | ||||
|             height: 6px; | ||||
|             border-radius: 6px; | ||||
|             background: linear-gradient(90deg, #45bfe9 0%, #01589c 100%); | ||||
|             animation: expandWidth 1s ease-in-out forwards; | ||||
|           } | ||||
| 
 | ||||
|           @keyframes expandWidth { | ||||
|             from { | ||||
|               width: 0; | ||||
|             } | ||||
|             to { | ||||
|               width: 100%; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .ui-wrap { | ||||
|  | ||||
| @ -11,11 +11,7 @@ | ||||
|           <div class="list-item-boday item-warp" :style="{ flex: listKeys.length }"> | ||||
|             <div class="item-content"> | ||||
|               <div class="label">{{ item.title }}</div> | ||||
|               <div class="val"> | ||||
|                 <div class="progress-warp" :style="{ width: item.percent + 'px' }"> | ||||
|                   <div class="progress"></div> | ||||
|                 </div> | ||||
|               </div> | ||||
|               <customProgress height="10px" :percent="item.percent"></customProgress> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
| @ -28,6 +24,7 @@ | ||||
| <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, | ||||
| @ -48,7 +45,11 @@ let refroll = ref(null); | ||||
| let datalist = computed(() => { | ||||
|   let maxwidth = refroll.value && refroll.value.clientWidth; | ||||
|   return list.map((m) => { | ||||
|     return { ...m, percent: parseInt(Number(m.value / max.value) * 200) }; | ||||
|     return { | ||||
|       ...m, | ||||
|       percent: Number((Number(parseInt(m.value) / max.value) * 100).toFixed(0)), | ||||
|       pwidth: parseInt(Number(parseInt(m.value) / max.value) * maxwidth), | ||||
|     }; | ||||
|   }); | ||||
| }); | ||||
| 
 | ||||
| @ -130,26 +131,6 @@ onMounted(() => {}); | ||||
|         width: 50px; | ||||
|         color: #fff; | ||||
|       } | ||||
|       .val { | ||||
|         width: calc(100% - 50px); | ||||
|         .progress-warp { | ||||
|           .progress { | ||||
|             height: 10px; | ||||
|             border-radius: 6px; | ||||
|             background: linear-gradient(90deg, #45bfe9 0%, #01589c 100%); | ||||
|             animation: expandWidth 1s ease-in-out forwards; | ||||
|           } | ||||
| 
 | ||||
|           @keyframes expandWidth { | ||||
|             from { | ||||
|               width: 0; | ||||
|             } | ||||
|             to { | ||||
|               width: 100%; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .list-item { | ||||
|  | ||||
| @ -5,6 +5,17 @@ | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| let seriesData = reactive([ | ||||
|   { value: 205.6 }, | ||||
|   { value: 308.7 }, | ||||
|   { value: 359.6 }, | ||||
|   { value: 452.6 }, | ||||
|   { value: 388.9 }, | ||||
|   { value: 508.7 }, | ||||
|   { value: 369.5 }, | ||||
|   { value: 610.8 }, | ||||
|   { value: 754.3 }, | ||||
| ]); | ||||
| 
 | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
| @ -53,18 +64,46 @@ const chartsData = reactive({ | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     series: [ | ||||
|       { | ||||
|         type: 'pictorialBar', | ||||
|         barCategoryGap: '40%', | ||||
|         barWidth: '100%', | ||||
|         symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z', | ||||
|         data: seriesData, | ||||
|         labelLine: { show: true }, | ||||
|         z: 10, | ||||
|         itemStyle: { | ||||
|           color: { | ||||
|             type: 'linear', | ||||
|             x: 0, | ||||
|             y: 0, | ||||
|             x2: 0, | ||||
|             y2: 1, | ||||
|             colorStops: [ | ||||
|               { | ||||
|                 offset: 0, | ||||
|                 color: '#000001', // 起始颜色 | ||||
|               }, | ||||
|               { | ||||
|                 offset: 1, | ||||
|                 color: '#0175b6', // 结束颜色 | ||||
|               }, | ||||
|             ], | ||||
|             global: false, // 默认为 false | ||||
|           }, | ||||
|         }, | ||||
|         label: { | ||||
|           show: false, | ||||
|           position: 'top', | ||||
|           formatter: '{c}', | ||||
|           color: 'white', | ||||
|           fontSize: 14, | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { value: 205.6 }, | ||||
|     { value: 308.7 }, | ||||
|     { value: 359.6 }, | ||||
|     { value: 452.6 }, | ||||
|     { value: 388.9 }, | ||||
|     { value: 508.7 }, | ||||
|     { value: 369.5 }, | ||||
|     { value: 610.8 }, | ||||
|     { value: 754.3 }, | ||||
|   ], | ||||
|   valData: seriesData, | ||||
| }); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
|  | ||||
| @ -0,0 +1,174 @@ | ||||
| <template> | ||||
|   <div class="plant-environment-warp"> | ||||
|     <div class="data-item-row"> | ||||
|       <div | ||||
|         v-for="(n, index) in datalist" | ||||
|         :key="index" | ||||
|         :style="{ | ||||
|           'background-image': 'url(' + getAssetsFile('images/plant/bg3.png') + ')', | ||||
|           width: 'calc((100% - 30px) /' + datalist.length + ')', | ||||
|         }" | ||||
|         class="data-item" | ||||
|       > | ||||
|         <div class="data-warp"> | ||||
|           <div class="data-pos"> | ||||
|             <div class="data-pos-center"> | ||||
|               <div class="pos-center"> | ||||
|                 <span class="label">{{ n.label }}</span> | ||||
|                 <div class="value"> | ||||
|                   <span>{{ n.value }}</span> | ||||
|                   <span class="unit">{{ n.unit }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="small-bg"> | ||||
|             <img :src="getAssetsFile('images/plant/bg6.png')" /> | ||||
|             <img :src="getAssetsFile('images/plant/' + n.icon)" class="img-icon" /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| import { ref, reactive, onMounted, watch } from 'vue'; | ||||
| import { useRouter } from 'vue-router'; | ||||
| import { useApp } from '@/hooks'; | ||||
| 
 | ||||
| const router = useRouter(); | ||||
| const props = defineProps({ | ||||
|   title: { | ||||
|     type: String, | ||||
|     default: '统计分析', | ||||
|   }, | ||||
|   postion: { | ||||
|     type: String, | ||||
|     default: 'left', | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| let topTitle = ref(''); | ||||
| let pos = ref(''); | ||||
| 
 | ||||
| const datalist = reactive([ | ||||
|   { label: '空气温度', value: 28.6, unit: '℃', icon: 'icon4.png' }, | ||||
|   { label: '空气湿度', value: 30, unit: '%', icon: 'icon3.png' }, | ||||
|   { label: '光照强度', value: 1000, unit: 'lux', icon: 'icon1.png' }, | ||||
|   { label: '降水量', value: 100, unit: 'mm', icon: 'icon2.png' }, | ||||
| ]); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   if (datalist.length) { | ||||
|     datalist.forEach((m, index) => { | ||||
|       let num = 0; | ||||
|       switch (index) { | ||||
|         case 0: | ||||
|           num = 20; | ||||
|           break; | ||||
|         case 1: | ||||
|           num = 30; | ||||
|           break; | ||||
|         case 2: | ||||
|           num = 1000; | ||||
|           break; | ||||
|         case 3: | ||||
|           num = 100; | ||||
|           break; | ||||
|         default: | ||||
|           num = 10; | ||||
|           break; | ||||
|       } | ||||
| 
 | ||||
|       m.value = (Math.random() + num).toFixed(2); | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => (props.title, props.postion), | ||||
|   () => { | ||||
|     topTitle.value = props.title; | ||||
|     pos.value = props.postion; | ||||
|   }, | ||||
|   { | ||||
|     deep: true, | ||||
|     immediate: true, | ||||
|   } | ||||
| ); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .plant-environment-warp { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   .data-item-row { | ||||
|     height: 100%; | ||||
|     width: 100%; | ||||
|     display: inline-flex; | ||||
|     justify-content: space-around; | ||||
|     flex-wrap: wrap; | ||||
|     gap: 10px; | ||||
|   } | ||||
|   .data-item { | ||||
|     height: 100%; | ||||
|     background-size: 100% 100%; | ||||
|     position: relative; | ||||
|   } | ||||
|   .data-warp { | ||||
|     padding: 8px 0; | ||||
|     text-align: center; | ||||
|     z-index: 1; | ||||
|     display: inline-flex; | ||||
|     justify-content: center; | ||||
|     .small-bg, | ||||
|     .data-pos { | ||||
|       display: inline-flex; | ||||
|       vertical-align: middle; | ||||
|       .data-pos-center { | ||||
|         display: inline-flex; | ||||
|         justify-content: space-around; | ||||
|         flex-direction: column; | ||||
|         height: 100%; | ||||
|         .pos-center { | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     .small-bg { | ||||
|       width: 38px; | ||||
|       height: 38px; | ||||
|       position: relative; | ||||
|       margin-top: 10%; | ||||
|       .img-icon { | ||||
|         position: absolute; | ||||
|         left: 50%; | ||||
|         top: 50%; | ||||
|         transform: translate(-50%, -50%); | ||||
|         width: 38%; | ||||
|         height: 38%; | ||||
|       } | ||||
|     } | ||||
|     .data-pos { | ||||
|       width: calc(100% - 54px); | ||||
|       .label, | ||||
|       .value { | ||||
|         display: inline-block; | ||||
|         width: 100%; | ||||
|       } | ||||
|       .label { | ||||
|         color: #fff; | ||||
|         font-size: 13px; | ||||
|       } | ||||
|       .value { | ||||
|         color: #6beff9; | ||||
|         font-size: 16px; | ||||
|         font-weight: bold; | ||||
|         margin-top: 6px; | ||||
|       } | ||||
|       .unit { | ||||
|         font-size: 10px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -1,18 +1,41 @@ | ||||
| <template> | ||||
|   <div class="irrigation-charts"> | ||||
|     <custom-echart-water-droplet height="100%" :option="option" /> | ||||
|     <div class="charts-content"> | ||||
|       <div class="water-droplet-bg" :style="{ 'background-image': 'url(' + getAssetsFile('images/plant/bg5.png') + ')' }"> | ||||
|         <div class="water-droplet"> | ||||
|           <custom-echart-water-droplet height="100%" :option="option" /> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="water-droplet-warp"> | ||||
|         <template v-for="(n, index) in itemlist" :key="index"> | ||||
|           <div class="water-droplet-item" :style="{ height: 'calc((100% - 20px) / ' + itemlist.length + ')' }"> | ||||
|             <div class="title" :style="{ 'background-image': 'url(' + getAssetsFile(n.bg1) + ')' }"> | ||||
|               <div class="title-val" :style="{ color: n.color }">{{ n.title }}</div> | ||||
|             </div> | ||||
|             <div class="tips" :style="{ 'background-image': 'url(' + getAssetsFile(n.bg2) + ')' }"> | ||||
|               <span class="tips-val">{{ n.tips }}</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </template> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| let percent = ref(0.6); | ||||
| let itemlist = reactive([ | ||||
|   { title: '智能灌溉', bg1: 'images/plant/bg8.png', bg2: 'images/plant/bg7.png', tips: '去浇水', color: '#4a90e2ff' }, | ||||
|   { title: '智能施肥', bg1: 'images/plant/bg9.png', bg2: 'images/plant/bg7.png', tips: '去施肥', color: '#50e3c2ff' }, | ||||
| ]); | ||||
| const option = reactive({ | ||||
|   backgroundColor: 'transparent', //背景色 | ||||
|   series: [ | ||||
|     { | ||||
|       name: '预估量', | ||||
|       type: 'liquidFill', | ||||
|       radius: '42%', | ||||
|       radius: '80%', | ||||
|       center: ['50%', '50%'], | ||||
|       backgroundStyle: { | ||||
|         color: 'transparent', | ||||
| @ -24,14 +47,14 @@ const option = reactive({ | ||||
|         position: ['50%', '45%'], | ||||
|         formatter: percent.value * 100 + '%', //显示文本, | ||||
|         textStyle: { | ||||
|           fontSize: '26px', //文本字号, | ||||
|           fontSize: '20px', //文本字号, | ||||
|           color: '#fff', | ||||
|         }, | ||||
|       }, | ||||
|       outline: { | ||||
|         borderDistance: 3, | ||||
|         itemStyle: { | ||||
|           borderWidth: 2, | ||||
|           borderWidth: 1, | ||||
|           borderColor: { | ||||
|             type: 'linear', | ||||
|             x: 1, | ||||
| @ -41,15 +64,15 @@ const option = reactive({ | ||||
|             colorStops: [ | ||||
|               { | ||||
|                 offset: 0, | ||||
|                 color: '#007DFF', | ||||
|                 color: 'rgba(255, 255, 255, 0.8)', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 0.6, | ||||
|                 color: 'rgba(45, 67, 114, 1)', | ||||
|                 color: 'rgba(255, 255, 255, 0.8)', | ||||
|               }, | ||||
|               { | ||||
|                 offset: 1, | ||||
|                 color: 'rgba(45, 67, 114, 1)', | ||||
|                 color: 'rgba(255, 255, 255, 0.8)', | ||||
|               }, | ||||
|             ], | ||||
|             globalCoord: false, | ||||
| @ -79,5 +102,78 @@ onMounted(() => {}); | ||||
| <style lang="scss" scoped> | ||||
| .irrigation-charts { | ||||
|   height: 100%; | ||||
|   .charts-content { | ||||
|     display: inline-flex; | ||||
|     justify-content: space-between; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     .water-droplet-bg { | ||||
|       display: inline-block; | ||||
|       width: 40%; | ||||
|       background-size: contain; | ||||
|       background-repeat: no-repeat; | ||||
|       background-position: center bottom; | ||||
|       position: relative; | ||||
|       .water-droplet { | ||||
|         position: absolute; | ||||
|         left: 50%; | ||||
|         top: 10%; | ||||
|         transform: translateX(-50%); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     .water-droplet-warp { | ||||
|       width: 60%; | ||||
|       padding: 0 10px; | ||||
|       display: inline-flex; | ||||
|       vertical-align: middle; | ||||
|       flex-direction: column; | ||||
|       .water-droplet-item { | ||||
|         width: 100%; | ||||
|       } | ||||
|       .title, | ||||
|       .tips { | ||||
|         display: inline-block; | ||||
|         color: #fff; | ||||
|         vertical-align: top; | ||||
|         .tips-val { | ||||
|           display: inline-flex; | ||||
|           line-height: 42px; | ||||
|           text-align: center; | ||||
|           font-size: 14px; | ||||
|           font-weight: bold; | ||||
|           transform: skewX(-13deg) translateY(-50%); | ||||
|           background: linear-gradient(to bottom, '#ff7e5f', '#548fff'); | ||||
|           -webkit-background-clip: text; | ||||
|           color: #fff; | ||||
|           letter-spacing: 2px; | ||||
|           text-shadow: -6px 0 0 1px #add8f1; | ||||
|           position: absolute; | ||||
|           left: 0; | ||||
|           top: 50%; | ||||
|         } | ||||
|       } | ||||
|       .title { | ||||
|         width: 40%; | ||||
|         height: 100%; | ||||
|         background-size: contain; | ||||
|         background-position: left bottom; | ||||
|         background-repeat: no-repeat; | ||||
|         .title-val { | ||||
|           width: 100%; | ||||
|           text-align: center; | ||||
|           line-height: 32px; | ||||
|         } | ||||
|       } | ||||
|       .tips { | ||||
|         width: 60%; | ||||
|         height: 100%; | ||||
|         background-size: 100% auto; | ||||
|         background-repeat: no-repeat; | ||||
|         background-position: left center; | ||||
|         position: relative; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -0,0 +1,25 @@ | ||||
| <template> | ||||
|   <div class="monitoring-screen-warp"> | ||||
|     <div class="monitoring-screen-content" :style="{ 'background-image': 'url(' + getAssetsFile('images/plant/bg2.png') + ')' }"></div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .monitoring-screen-warp { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   box-sizing: border-box; | ||||
|   .monitoring-screen-content { | ||||
|     background-size: 100% 100%; | ||||
|     background-repeat: no-repeat; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     padding: 10px 0; | ||||
|     div { | ||||
|       box-sizing: border-box; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,73 @@ | ||||
| <template> | ||||
|   <div class="notice-bar-warp" :style="{ height: height }"> | ||||
|     <div class="notice-bar-pos"> | ||||
|       <div class="notice-icon"> | ||||
|         <img :src="getAssetsFile('images/plant/icon5.png')" /> | ||||
|       </div> | ||||
|       <div class="notice-bar" :style="{ 'line-height': height }"> | ||||
|         <div class="scrolling-text"> | ||||
|           <span>{{ text }}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| defineProps({ | ||||
|   text: { | ||||
|     type: String, | ||||
|     required: true, | ||||
|     default: '这是一条滚动通知消息,请注意查看!', | ||||
|   }, | ||||
|   height: { | ||||
|     type: String || Number, | ||||
|     default: '40px', | ||||
|   }, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style scoped lang="scss"> | ||||
| .notice-bar-warp { | ||||
|   width: 100%; | ||||
|   display: inline-flex; | ||||
|   flex-direction: column; | ||||
|   justify-content: center; | ||||
|   .notice-bar-pos { | ||||
|     display: inline-flex; | ||||
|     width: 100%; | ||||
|   } | ||||
|   .notice-icon { | ||||
|     display: inline-block; | ||||
|     vertical-align: middle; | ||||
|     width: 30px; | ||||
|     img { | ||||
|       width: 80%; | ||||
|       height: 80%; | ||||
|       margin: 10% 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| .notice-bar { | ||||
|   display: inline-block; | ||||
|   overflow: hidden; | ||||
|   width: calc(100% - 30px); | ||||
| } | ||||
| 
 | ||||
| .scrolling-text { | ||||
|   white-space: nowrap; | ||||
|   animation: scroll-left 10s linear infinite; | ||||
|   color: #fff; | ||||
| } | ||||
| 
 | ||||
| @keyframes scroll-left { | ||||
|   0% { | ||||
|     transform: translateX(100%); | ||||
|   } | ||||
|   100% { | ||||
|     transform: translateX(-100%); | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -71,16 +71,7 @@ const chartsData = reactive({ | ||||
|       y2: '20%', | ||||
|     }, | ||||
|   }, | ||||
|   valData: [ | ||||
|     // { name: '1月', value: 40, type: '蝗虫', seriesType: 'bar', ...itemStyle, stack: '1月' }, | ||||
|     // { name: '1月', value: 30, type: '飞蛾', seriesType: 'bar', ...itemStyle, stack: '1月' }, | ||||
|     // { name: '1月', value: 100, type: '其他', seriesType: 'bar', ...itemStyle, stack: '1月' }, | ||||
|     // { name: '1月', value: 60, type: '蚜虫', seriesType: 'bar', ...itemStyle, stack: '1月' }, | ||||
|     // { name: '2月', value: 20, type: '蝗虫', seriesType: 'bar', ...itemStyle, stack: '2月' }, | ||||
|     // { name: '2月', value: 20, type: '飞蛾', seriesType: 'bar', ...itemStyle, stack: '2月' }, | ||||
|     // { name: '2月', value: 80, type: '其他', seriesType: 'bar', ...itemStyle, stack: '2月' }, | ||||
|     // { name: '2月', value: 40, type: '蚜虫', seriesType: 'bar', ...itemStyle, stack: '2月' }, | ||||
|   ], | ||||
|   valData: [], | ||||
| }); | ||||
| 
 | ||||
| const randomVal = (num) => { | ||||
| @ -113,7 +104,7 @@ let handelData = computed(() => { | ||||
|   list.map((m, indexm) => { | ||||
|     return { ...m, value: Number(Number(m.value) + Math.random() + indexm).toFixed(0) }; | ||||
|   }); | ||||
|   console.info('handelData', list); | ||||
|   // console.info('handelData', list); | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,22 @@ | ||||
| <template> | ||||
|   <div class="plant-gs-warp"> | ||||
|     <div class="plant-gs-content" :style="{ 'background-image': 'url(' + getAssetsFile('images/plant/bg1.png') + ')' }"></div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .plant-gs-warp { | ||||
|   height: 100%; | ||||
|   padding: 10px 0; | ||||
|   width: 100%; | ||||
|   box-sizing: border-box; | ||||
|   .plant-gs-content { | ||||
|     background-size: 100% 100%; | ||||
|     background-repeat: no-repeat; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,274 @@ | ||||
| <template> | ||||
|   <div class="water-detection-charts"> | ||||
|     <custom-echart-line-line :chart-data="chartsData.valData" height="100%" :option="chartsData.option" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| const legendData = ['矿物质', '钠元素']; | ||||
| 
 | ||||
| let series = reactive([ | ||||
|   { | ||||
|     name: legendData[0], | ||||
|     type: 'line', | ||||
|     symbol: 'none', // 默认是空心圆(中间是白色的),改成实心圆 | ||||
|     smooth: true, | ||||
|     lineStyle: { | ||||
|       normal: { | ||||
|         width: 1, | ||||
|         color: '#00e6fb', // 线条颜色 | ||||
|       }, | ||||
|     }, | ||||
|     areaStyle: { | ||||
|       normal: { | ||||
|         //线性渐变,前4个参数分别是x0,y0,x2,y2(范围0~1);相当于图形包围盒中的百分比。如果最后一个参数是‘true’,则该四个值是绝对像素位置。 | ||||
|         color: { | ||||
|           type: 'linear', // 线性渐变 | ||||
|           x: 0, | ||||
|           y: 0, | ||||
|           x2: 0, | ||||
|           y2: 1, | ||||
|           colorStops: [ | ||||
|             { offset: 0, color: 'rgba(2, 113, 146,1)' }, | ||||
|             { offset: 0.4, color: 'rgba(2, 83, 111,1)' }, | ||||
|             { offset: 0.7, color: 'rgba(2, 64, 77,1)' }, | ||||
|             { offset: 1, color: 'rgba(1, 18, 43)' }, | ||||
|           ], | ||||
|           global: false, // 默认为 false | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     data: [0.64, 0.34, 0.7, 0.44, 0.74, 0.12, 0.65, 0.41, 0.85, 0.96, 0.23, 0.16], | ||||
|     markLine: { | ||||
|       symbol: 'none', | ||||
|       silent: true, | ||||
|       lineStyle: { | ||||
|         color: 'red', // 确保颜色可见 | ||||
|         width: 2, // 确保线条宽度足够 | ||||
|         type: 'solid', | ||||
|       }, | ||||
|       data: [ | ||||
|         { yAxis: 0.5, name: '基准线1' }, | ||||
|         { yAxis: 0.7, name: '基准线2' }, | ||||
|       ], | ||||
|       label: { | ||||
|         show: true, | ||||
|         position: 'end', | ||||
|         formatter: '{b}: {c}', | ||||
|         color: '#fff', | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|   { | ||||
|     name: legendData[1], | ||||
|     type: 'line', | ||||
|     symbol: 'none', // 默认是空心圆(中间是白色的),改成实心圆 | ||||
|     smooth: true, | ||||
|     lineStyle: { | ||||
|       normal: { | ||||
|         width: 1, | ||||
|         color: 'rgb(0, 254, 150)', // 线条颜色 | ||||
|       }, | ||||
|     }, | ||||
|     areaStyle: { | ||||
|       normal: { | ||||
|         //线性渐变,前4个参数分别是x0,y0,x2,y2(范围0~1);相当于图形包围盒中的百分比。如果最后一个参数是‘true’,则该四个值是绝对像素位置。 | ||||
|         color: { | ||||
|           type: 'linear', // 线性渐变 | ||||
|           x: 0, | ||||
|           y: 0, | ||||
|           x2: 0, | ||||
|           y2: 1, | ||||
|           colorStops: [ | ||||
|             { offset: 0, color: 'rgb(42, 140, 102)' }, | ||||
|             { offset: 0.6, color: 'rgb(14, 82, 63)' }, | ||||
|             { offset: 1, color: 'rgb(1, 18, 43)' }, | ||||
|           ], | ||||
|           global: false, // 默认为 false | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     data: [0.14, 0.73, 0.38, 0.46, 0.65, 0.17, 0.89, 0.95, 0.47, 0.19, 0.86, 0.58], | ||||
|   }, | ||||
| ]); | ||||
| const currentMonth = ref(new Date().getMonth() + 1); | ||||
| const xPoint = computed(() => { | ||||
|   let list = []; | ||||
|   console.info('111', currentMonth.value); | ||||
|   for (let i = 1; i < 13; i++) { | ||||
|     let mouth = i < 10 ? i : i; | ||||
|     list.push(mouth + '月'); | ||||
|   } | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     backgroundColor: '#00001b', | ||||
|     grid: { | ||||
|       left: 20, | ||||
|       right: 20, | ||||
|       bottom: '5%', | ||||
|       top: '20%', | ||||
|       containLabel: true, | ||||
|     }, | ||||
|     tooltip: { | ||||
|       trigger: 'axis', | ||||
|       backgroundColor: 'rgba(33, 85, 154, .6)', | ||||
|       borderWidth: 1, | ||||
|       borderColor: { | ||||
|         type: 'linear', | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { | ||||
|             offset: 0, | ||||
|             color: 'rgba(85, 149, 233, .6)', // 0% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 1, | ||||
|             color: 'rgba(85, 149, 233, 0)', // 100% 处的颜色 | ||||
|           }, | ||||
|         ], | ||||
|         global: false, // 缺省为 false | ||||
|       }, | ||||
|       padding: 8, | ||||
|       textStyle: { | ||||
|         color: '#fff', | ||||
|       }, | ||||
|       axisPointer: { | ||||
|         lineStyle: { | ||||
|           type: 'dashed', | ||||
|           color: 'rgba(255, 255, 255, .6)', | ||||
|         }, | ||||
|       }, | ||||
|       extraCssText: 'box-shadow: 2px 2px 16px 1px rgba(0, 39, 102, 0.16)', | ||||
|       formatter: function (params) { | ||||
|         let content = `<div style='font-size: 14px; color: #fff;'>${params[0].name}</div>`; | ||||
|         if (Array.isArray(params)) { | ||||
|           for (let i = 0; i < params.length; i++) { | ||||
|             content += ` | ||||
|                        <div style='display: flex; align-items: center; padding: 4px; background: #21559A; margin-top: 4px; color: #fff;'> | ||||
|                          <div style='width: 10px; height: 10px; background: ${params[i].color}; margin-right: 8px;'></div> | ||||
|                          <div style='font-size: 12px; margin-right: 32px;'>${params[i].seriesName}</div> | ||||
|                          <div style='font-size: 14px;'>${params[i].value}</div> | ||||
|                        </div> | ||||
|                      `; | ||||
|           } | ||||
|         } | ||||
|         return content; | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: Array.from(legendData), | ||||
|       left: 'center', // 距离左侧10%的位置 | ||||
|       top: '0', // 垂直居中 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     // legend: [ | ||||
|     //   { | ||||
|     //     data: [ | ||||
|     //       { | ||||
|     //         name: legendData[0], | ||||
|     //         icon: 'rect', | ||||
|     //       }, | ||||
|     //     ], | ||||
|     //     itemWidth: 10, | ||||
|     //     itemHeight: 2, | ||||
|     //     top: '2%', | ||||
|     //     left: '40%', | ||||
|     //     textStyle: { | ||||
|     //       color: '#ADD7FF', | ||||
|     //       fontSize: 12, | ||||
|     //     }, | ||||
|     //   }, | ||||
|     //   { | ||||
|     //     top: '2%', | ||||
|     //     left: '55%', | ||||
|     //     textStyle: { | ||||
|     //       color: '#ADD7FF', | ||||
|     //       fontSize: 14, | ||||
|     //     }, | ||||
|     //     itemWidth: 18, | ||||
|     //     itemHeight: 2, | ||||
|     //     data: [ | ||||
|     //       { | ||||
|     //         name: legendData[1], | ||||
|     //         icon: 'rect', | ||||
|     //       }, | ||||
|     //     ], | ||||
|     //   }, | ||||
|     // ], | ||||
|     xAxis: { | ||||
|       type: 'category', | ||||
|       boundaryGap: false, | ||||
|       axisLabel: { | ||||
|         interval: 0, // 设置为 1,表示『隔一个标签显示一个标签』 | ||||
|         textStyle: { | ||||
|           color: '#DEEBFF', | ||||
|           fontStyle: 'normal', | ||||
|           fontSize: 10, | ||||
|         }, | ||||
|       }, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLine: { | ||||
|         // 坐标轴轴线相关设置 | ||||
|         lineStyle: { | ||||
|           color: 'rgba(77, 128, 254, 0.2)', | ||||
|         }, | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: false, | ||||
|       }, | ||||
|       data: xPoint.value, | ||||
|     }, | ||||
|     yAxis: { | ||||
|       type: 'value', | ||||
|       name: ' ', | ||||
|       nameTextStyle: { | ||||
|         color: '#DEEBFF', | ||||
|         fontSize: 14, | ||||
|         padding: [0, 0, 0, -30], | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         interval: 0, // 设置为 1,表示『隔一个标签显示一个标签』 | ||||
|         textStyle: { | ||||
|           color: '#DEEBFF', | ||||
|           fontStyle: 'normal', | ||||
|           fontSize: 12, | ||||
|         }, | ||||
|       }, | ||||
|       axisTick: { | ||||
|         show: false, | ||||
|       }, | ||||
|       axisLine: { | ||||
|         // 坐标轴轴线相关设置 | ||||
|         lineStyle: { | ||||
|           color: 'rgba(77, 128, 254, 0.2)', | ||||
|         }, | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: false, | ||||
|       }, | ||||
|     }, | ||||
|     series: series, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .water-detection-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,290 @@ | ||||
| <template> | ||||
|   <div class="yield-charts"> | ||||
|     <custom-echart-pictorial-bar :chart-data="chartsData.valData" height="100%" :option="chartsData.option" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| let itemStyle = reactive({ | ||||
|   itemStyle: { borderRadius: [8, 8, 0, 0] }, | ||||
| }); | ||||
| 
 | ||||
| let legendList = reactive(['总产量', '种植面积']); | ||||
| const payload = { | ||||
|   id: '', | ||||
|   data: { | ||||
|     title: legendList, | ||||
|     unit: ['%'], | ||||
|     xAxis: ['耿马镇', '勐撒镇', '勐永镇', '孟定镇', '勐简乡', '贺派乡', '四排山乡', '芒洪乡', '大兴乡'], | ||||
|     data1: [20, 80, 100, 40, 34, 90, 60, 20, 80], | ||||
|     data2: [10, 100, 80, 30, 50, 100, 50, 10, 90], | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| const unit = payload.data.unit || []; | ||||
| const xAxis = payload.data.xAxis || []; | ||||
| const data1 = payload.data.data1 || []; | ||||
| const data2 = payload.data.data2 || []; | ||||
| const title = payload.data.title || []; | ||||
| 
 | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     backgroundColor: 'transparent', | ||||
|     grid: { | ||||
|       left: '3%', | ||||
|       right: '4%', | ||||
|       bottom: '1%', | ||||
|       top: '15%', | ||||
|       containLabel: true, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: Array.from(legendList), | ||||
|       left: 'center', // 距离左侧10%的位置 | ||||
|       top: '0', // 垂直居中 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     tooltip: { | ||||
|       // 触发类型  经过轴触发axis  经过轴触发item | ||||
|       trigger: 'axis', | ||||
|       backgroundColor: 'rgba(9, 30, 60, 0.6)', | ||||
|       extraCssText: 'box-shadow: 0 0 8px rgba(0, 128, 255, 0.27) inset;', | ||||
|       borderWidth: 0, | ||||
|       confine: false, | ||||
|       appendToBody: true, | ||||
|       textStyle: { | ||||
|         color: '#fff', | ||||
|         fontSize: 10, | ||||
|       }, | ||||
|       // 轴触发提示才有效 | ||||
|       axisPointer: { | ||||
|         type: 'shadow', | ||||
|       }, | ||||
|       shadowStyle: { | ||||
|         color: 'rgba(157, 168, 245, 0.1)', | ||||
|       }, | ||||
| 
 | ||||
|       formatter: (data) => { | ||||
|         var tip = '<h5 class="echarts-tip-h5">' + data[0].name + '</h5>'; | ||||
|         data.forEach((item) => { | ||||
|           let unit = ''; | ||||
|           if (item.seriesType === 'bar') { | ||||
|             tip += '<div class="echarts-tip-div">'; | ||||
|             // tip += '<div class="left">' + item.marker + item.seriesName + ':</div>'; | ||||
|             tip += '<div class="right">' + item.seriesName + ':' + item.value + unit + '</div>'; | ||||
|             tip += '</div>'; | ||||
|           } | ||||
|         }); | ||||
|         return tip; | ||||
|       }, | ||||
|     }, | ||||
|     xAxis: { | ||||
|       data: xAxis, | ||||
|       axisLine: { | ||||
|         lineStyle: { | ||||
|           type: 'solid', | ||||
|           color: '#4176a3', | ||||
|           width: '0.5', //坐标线的宽度 | ||||
|         }, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         textStyle: { | ||||
|           color: '#fff', //底部文字颜色 | ||||
|           fontSize: 12, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     dataZoom: [ | ||||
|       { | ||||
|         type: 'slider', // 滑动条型数据区域缩放组件 | ||||
|         startValue: 0, // 数据窗口起始值的索引 | ||||
|         endValue: 5, // 数据窗口结束值的索引 | ||||
|       }, | ||||
|       { | ||||
|         type: 'inside', // 支持鼠标滚轮和触控板缩放和平移 | ||||
|         startValue: 0, | ||||
|         endValue: 5, | ||||
|       }, | ||||
|     ], | ||||
|     yAxis: [ | ||||
|       { | ||||
|         name: ' ', | ||||
|         nameTextStyle: { | ||||
|           align: 'left', | ||||
|           fontSize: 11, | ||||
|           color: '#4176a3', | ||||
|         }, | ||||
|         type: 'value', | ||||
|         axisLine: { | ||||
|           show: false, | ||||
|           lineStyle: { | ||||
|             color: 'transparent', //左边框颜色 | ||||
|           }, | ||||
|         }, | ||||
|         splitLine: { show: false }, | ||||
|         axisTick: { show: false }, | ||||
|         axisLabel: { | ||||
|           show: true, | ||||
|           fontSize: 12, | ||||
|           textStyle: { | ||||
|             color: '#ADD6FF', //左文字颜色 | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|     series: [ | ||||
|       { | ||||
|         name: title[0], | ||||
|         type: 'bar', | ||||
|         barWidth: 10, | ||||
|         showBackground: true, | ||||
|         backgroundStyle: { | ||||
|           color: 'rgba(21,136,209,0.1)', | ||||
|         }, | ||||
|         itemStyle: { | ||||
|           color: { | ||||
|             type: 'linear', // 线性渐变 | ||||
|             x: 0, | ||||
|             y: 0, | ||||
|             x2: 0, | ||||
|             y2: 1, | ||||
|             colorStops: [ | ||||
|               { offset: 0, color: '#45bfe9' }, | ||||
|               { offset: 1, color: '#01589c' }, | ||||
|             ], | ||||
|             global: false, // 默认为 false | ||||
|           }, | ||||
|         }, | ||||
|         data: data1, | ||||
|         z: 0, | ||||
|         zlevel: 0, | ||||
|       }, | ||||
|       { | ||||
|         type: 'pictorialBar', | ||||
|         barWidth: 10, | ||||
|         itemStyle: { | ||||
|           color: '#021C46', //数据的间隔颜色 | ||||
|         }, | ||||
|         symbolRepeat: 'true', | ||||
|         symbolMargin: 3, | ||||
|         symbol: 'rect', | ||||
|         symbolSize: [30, 4], | ||||
|         data: data1, | ||||
|         z: 1, | ||||
|         zlevel: 0, | ||||
|         label: { | ||||
|           show: false, | ||||
|           position: 'top', | ||||
|           fontSize: 14, | ||||
|           color: '#fff', //柱状顶部文字颜色 | ||||
|           formatter: function (params) { | ||||
|             return params.data; | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         name: title[1], | ||||
|         type: 'bar', | ||||
|         barWidth: 10, | ||||
|         showBackground: true, | ||||
|         backgroundStyle: { | ||||
|           color: 'rgba(21,136,209,0.1)', | ||||
|         }, | ||||
|         itemStyle: { | ||||
|           color: { | ||||
|             type: 'linear', // 线性渐变 | ||||
|             x: 0, | ||||
|             y: 0, | ||||
|             x2: 0, | ||||
|             y2: 1, | ||||
|             colorStops: [ | ||||
|               { offset: 0, color: '#6beff9' }, | ||||
|               { offset: 1, color: '#2f888f' }, | ||||
|             ], | ||||
|             global: false, // 默认为 false | ||||
|           }, | ||||
|         }, | ||||
|         data: data2, | ||||
|         z: 0, | ||||
|         zlevel: 0, | ||||
|       }, | ||||
|       { | ||||
|         type: 'pictorialBar', | ||||
|         barWidth: 10, | ||||
|         itemStyle: { | ||||
|           color: '#021C46', //数据的间隔颜色 | ||||
|         }, | ||||
|         symbolRepeat: 'true', | ||||
|         symbolMargin: 3, | ||||
|         symbol: 'rect', | ||||
|         symbolSize: [30, 4], | ||||
|         data: data2, | ||||
|         z: 1, | ||||
|         zlevel: 0, | ||||
|         label: { | ||||
|           show: false, | ||||
|           position: 'top', | ||||
|           fontSize: 14, | ||||
|           color: '#fff', //柱状顶部文字颜色 | ||||
|           formatter: function (params) { | ||||
|             return params.data; | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { name: '1月', value: 40, type: '蝗虫', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '1月', value: 30, type: '飞蛾', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '1月', value: 100, type: '其他', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '1月', value: 60, type: '蚜虫', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '2月', value: 20, type: '蝗虫', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '2月', value: 20, type: '飞蛾', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '2月', value: 80, type: '其他', seriesType: 'bar', ...itemStyle }, | ||||
|     { name: '2月', value: 40, type: '蚜虫', seriesType: 'bar', ...itemStyle }, | ||||
|   ], | ||||
| }); | ||||
| 
 | ||||
| const randomVal = (num) => { | ||||
|   let list = []; | ||||
|   for (let i = 0; i < legendList.length; i++) { | ||||
|     let addNum = [10, 8, 2, 5]; | ||||
|     let val = { | ||||
|       name: num + '月', | ||||
|       value: Number(Math.random() * 100 + addNum[i]).toFixed(2), | ||||
|       seriesType: 'bar', | ||||
|       type: legendList[i], | ||||
|       ...itemStyle, | ||||
|     }; | ||||
|     list[i] = val; | ||||
|   } | ||||
|   return list; | ||||
| }; | ||||
| let handelData = computed(() => { | ||||
|   let list = []; | ||||
|   let maxMouth = 12; | ||||
|   for (let i = 0; i < maxMouth; i++) { | ||||
|     let val = randomVal(i + 1); | ||||
|     list = [...list, ...val]; | ||||
|   } | ||||
| 
 | ||||
|   list.map((m) => { | ||||
|     return { ...m, value: Number(m.value + Math.random() + 10).toFixed(2) }; | ||||
|   }); | ||||
|   // console.info('handelData', list); | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .yield-charts { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div class="data-home-index"> | ||||
|   <div class="data-plant-index"> | ||||
|     <baseBg :name-val="'plant'" top-title="智慧种植管理系统"> | ||||
|       <template #center> | ||||
|         <el-row style="width: 100%; height: 100%"> | ||||
| @ -27,18 +27,28 @@ | ||||
|             </div> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <el-row style="height: 60%"> | ||||
|               <el-col :span="24"></el-col> | ||||
|             <el-row style="height: 67%"> | ||||
|               <el-col :span="24" class="center-top"> | ||||
|                 <div class="notice"> | ||||
|                   <noticeBar :height="'40px'"></noticeBar> | ||||
|                 </div> | ||||
|                 <div class="top"> | ||||
|                   <environment></environment> | ||||
|                 </div> | ||||
|                 <div class="map-gis"> | ||||
|                   <plantgs></plantgs> | ||||
|                 </div> | ||||
|               </el-col> | ||||
|             </el-row> | ||||
|             <el-row style="height: 40%"> | ||||
|               <el-col :span="12"> | ||||
|             <el-row style="height: 33%" :gutter="30"> | ||||
|               <el-col :span="12" style="height: 100%"> | ||||
|                 <customBack top-title="水肥检测分析" :top-postion="'left'"> | ||||
|                   <template #back> | ||||
|                     <waterfertilizerCharts></waterfertilizerCharts> | ||||
|                   </template> | ||||
|                 </customBack> | ||||
|               </el-col> | ||||
|               <el-col :span="12"> | ||||
|               <el-col :span="12" style="height: 100%"> | ||||
|                 <customBack top-title="智慧水肥灌溉" :top-postion="'right'"> | ||||
|                   <template #back> | ||||
|                     <irrigationCharts></irrigationCharts> | ||||
| @ -50,17 +60,23 @@ | ||||
|           <el-col :span="6" class="right-charts"> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="智慧监控 A区 QQI" :top-postion="'right'"> | ||||
|                 <template #back></template> | ||||
|                 <template #back> | ||||
|                   <monitoringScreen></monitoringScreen> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="种植产量分析" :top-postion="'right'"> | ||||
|                 <template #back></template> | ||||
|                 <template #back> | ||||
|                   <yieldCharts></yieldCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="水质检测分析" :top-postion="'right'"> | ||||
|                 <template #back></template> | ||||
|                 <template #back> | ||||
|                   <waterdetectionCharts></waterdetectionCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
| @ -77,9 +93,15 @@ import insectPestsCharts from './components/insectPestsCharts'; | ||||
| import pathologyCharts from './components/pathologyCharts.vue'; | ||||
| import waterfertilizerCharts from './components/waterfertilizerCharts.vue'; | ||||
| import irrigationCharts from './components/irrigationCharts.vue'; | ||||
| import yieldCharts from './components/yieldCharts.vue'; | ||||
| import waterdetectionCharts from './components/waterdetectionCharts.vue'; | ||||
| import environment from './components/environment.vue'; | ||||
| import plantgs from './components/plantgs.vue'; | ||||
| import monitoringScreen from './components/monitoringScreen.vue'; | ||||
| import noticeBar from './components/noticeBar.vue'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .data-home-index { | ||||
| .data-plant-index { | ||||
|   .left-charts { | ||||
|     display: flex; | ||||
|     justify-content: space-around; | ||||
| @ -103,5 +125,24 @@ import irrigationCharts from './components/irrigationCharts.vue'; | ||||
|     width: 100%; | ||||
|     height: calc((100% - 30px) / 3); | ||||
|   } | ||||
| 
 | ||||
|   .center-top { | ||||
|     padding: 16px; | ||||
|     .notice, | ||||
|     .top, | ||||
|     .map-gis { | ||||
|       display: inline-block; | ||||
|       width: 100%; | ||||
|     } | ||||
|     .notice { | ||||
|       height: 40px; | ||||
|     } | ||||
|     .top { | ||||
|       height: 80px; | ||||
|     } | ||||
|     .map-gis { | ||||
|       height: calc(100% - 140px); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -0,0 +1,326 @@ | ||||
| <template> | ||||
|   <div class="code-num-charts"> | ||||
|     <div class="code-num-txt" :style="{ 'background-image': 'url(' + getAssetsFile('images/trace/bg1.png') + ')' }"> | ||||
|       <div class="num-txt-pos"> | ||||
|         <template v-for="(n, index) in valData" :key="index"> | ||||
|           <div class="num-txt"> | ||||
|             <div class="val">{{ n.value }}</div> | ||||
|             <div class="label">{{ n.name }}</div> | ||||
|           </div> | ||||
|         </template> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="code-pie"> | ||||
|       <custom-echart-pie-gauge :chart-data="chartsData.valData" height="100%" :option="chartsData.option" /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| let valData = reactive([ | ||||
|   { value: 205.6, name: '生产溯源码' }, | ||||
|   { value: 308.7, name: '有效溯源码' }, | ||||
| ]); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     backgroundColor: 'transparent', | ||||
|     title: { | ||||
|       zlevel: 0, | ||||
|       text: 806, | ||||
|       subtext: '设备管理', | ||||
|       top: '38%', | ||||
|       left: '80%', | ||||
|       textAlign: 'center', | ||||
|       textStyle: { | ||||
|         color: '#fff', | ||||
|         fontSize: 14, | ||||
|       }, | ||||
|       subtextStyle: { | ||||
|         fontSize: 10, | ||||
|         color: '#fff', | ||||
|       }, | ||||
|       show: false, | ||||
|     }, | ||||
|     color: [ | ||||
|       { | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { offset: 0, color: 'rgba(40, 218, 239, 1)' }, | ||||
|           { offset: 1, color: 'rgba(130, 249, 255, 0.8)' }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 1, | ||||
|         y2: 0, | ||||
|         colorStops: [ | ||||
|           { offset: 0, color: 'rgba(198, 201, 24, 1)' }, | ||||
|           { offset: 1, color: 'rgba(198, 201, 24, 0.8)' }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 1, | ||||
|         y: 1, | ||||
|         x2: 0, | ||||
|         y2: 0, | ||||
|         colorStops: [ | ||||
|           { | ||||
|             offset: 0, | ||||
|             color: 'rgba(15, 44, 88, 1)', // 0% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 0.7, | ||||
|             color: 'rgba(40, 55, 255, 1)', // 100% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 1, | ||||
|             color: 'rgba(244, 245, 255, 1)', // 100% 处的颜色 | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 1, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { | ||||
|             offset: 0, | ||||
|             color: 'rgba(75, 238, 114, 0.2)', // 0% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 1, | ||||
|             color: 'rgba(75, 238, 114, 1)', // 100% 处的颜色 | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { | ||||
|             offset: 0, | ||||
|             color: 'rgba(255, 19, 0, 0.2)', // 0% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 1, | ||||
|             color: 'rgba(251, 95, 79, 1)', // 100% 处的颜色 | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { | ||||
|       type: 'pie', | ||||
|       name: '外层细圆环', | ||||
|       radius: ['58%', '60%'], | ||||
|       center: ['80%', '50%'], | ||||
|       hoverAnimation: true, | ||||
|       startAngle: 0, | ||||
|       clockWise: false, | ||||
|       itemStyle: { | ||||
|         normal: { | ||||
|           color: 'rgba(40, 218, 239, 0.8)', | ||||
|         }, | ||||
|       }, | ||||
|       label: { | ||||
|         show: false, | ||||
|       }, | ||||
|       data: [10], | ||||
|     }, | ||||
|     { | ||||
|       type: 'pie', | ||||
|       name: '内层细圆环', | ||||
|       radius: ['38%', '40%'], | ||||
|       center: ['80%', '50%'], | ||||
|       hoverAnimation: true, | ||||
|       startAngle: 0, | ||||
|       clockWise: false, | ||||
|       itemStyle: { | ||||
|         normal: { | ||||
|           color: 'rgba(40, 218, 239, 0.5)', | ||||
|         }, | ||||
|       }, | ||||
|       label: { | ||||
|         show: false, | ||||
|       }, | ||||
|       data: [10], | ||||
|     }, | ||||
|     { | ||||
|       name: '', | ||||
|       type: 'pie', | ||||
|       startAngle: 0, | ||||
|       radius: 70, | ||||
|       clockWise: false, | ||||
|       hoverAnimation: false, | ||||
|       center: ['80%', '50%'], | ||||
|       itemStyle: { | ||||
|         normal: { | ||||
|           labelLine: { | ||||
|             show: false, | ||||
|           }, | ||||
|           color: { | ||||
|             type: 'radial', | ||||
|             x: 0.5, | ||||
|             y: 0.5, | ||||
|             r: 0.5, | ||||
|             colorStops: [ | ||||
|               { offset: 1, color: 'rgba(129, 197, 200, 0.1)' }, | ||||
|               { offset: 0, color: 'rgba(129, 197, 200, 0)' }, | ||||
|             ], | ||||
|             globalCoord: false, | ||||
|           }, | ||||
|           shadowBlur: 10, | ||||
|         }, | ||||
|       }, | ||||
|       data: [ | ||||
|         { | ||||
|           value: 100, | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|     //环形 | ||||
|     { | ||||
|       name: '', | ||||
|       type: 'pie', | ||||
|       clockwise: false, | ||||
|       startAngle: -90, | ||||
|       radius: ['45%', '55%'], | ||||
|       center: ['80%', '50%'], | ||||
|       hoverAnimation: false, | ||||
|       label: { | ||||
|         normal: { | ||||
|           show: false, | ||||
|         }, | ||||
|         emphasis: { | ||||
|           show: false, | ||||
|         }, | ||||
|       }, | ||||
|       zlevel: 1, | ||||
|       labelLine: { | ||||
|         normal: { | ||||
|           show: false, | ||||
|         }, | ||||
|       }, | ||||
|       data: valData, | ||||
|     }, | ||||
|     //环形分割线 | ||||
|     { | ||||
|       name: '分割线', | ||||
|       type: 'gauge', | ||||
|       radius: '75%', | ||||
|       center: ['80%', '50%'], | ||||
|       clockwise: true, | ||||
|       startAngle: 90, // 起始角度 | ||||
|       endAngle: -360, // 结束角度 | ||||
|       splitNumber: 50, // 分割线数量 | ||||
|       zlevel: 2, | ||||
|       detail: { | ||||
|         offsetCenter: [10, 20], | ||||
|         formatter: ' ', | ||||
|       }, | ||||
|       axisLine: { | ||||
|         show: false, // 隐藏轴线 | ||||
|       }, | ||||
|       axisTick: { | ||||
|         show: false, // 隐藏刻度 | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: true, | ||||
|         length: 10, // 分割线的长度 | ||||
|         lineStyle: { | ||||
|           color: '#1e4960', | ||||
|           width: 1, // 分割线的宽度 | ||||
|         }, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         show: false, // 隐藏标签 | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| 
 | ||||
| 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> | ||||
| div { | ||||
|   box-sizing: border-box; | ||||
| } | ||||
| .code-num-charts { | ||||
|   height: 100%; | ||||
| 
 | ||||
|   position: relative; | ||||
|   .code-num-txt { | ||||
|     position: absolute; | ||||
|     left: 0; | ||||
|     top: 50%; | ||||
|     width: 80%; | ||||
|     transform: translateY(-50%); | ||||
|     background-size: contain; | ||||
|     background-repeat: no-repeat; | ||||
|     background-position: left center; | ||||
|     height: 100%; | ||||
|     .num-txt-pos { | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|       display: inline-flex; | ||||
|       justify-content: center; | ||||
|       flex-direction: column; | ||||
|     } | ||||
|     .num-txt { | ||||
|       width: 72%; | ||||
|       display: inline-flex; | ||||
|       justify-content: space-between; | ||||
|       padding: 0 16px; | ||||
|       line-height: 50px; | ||||
|       .val, | ||||
|       .label { | ||||
|         vertical-align: middle; | ||||
|         display: inline-flex; | ||||
|       } | ||||
|       .val { | ||||
|         font-size: 18px; | ||||
|         font-weight: bold; | ||||
|         background: linear-gradient(360deg, #34c7d1, #fff); /* 渐变颜色 */ | ||||
|         -webkit-background-clip: text; /* 裁剪背景为文字形状 */ | ||||
|         background-clip: text; | ||||
|         letter-spacing: -1px; | ||||
|         -webkit-text-fill-color: transparent; /* 设置文字颜色为透明 */ | ||||
|       } | ||||
|       .label { | ||||
|         font-size: 12px; | ||||
|         font-weight: bold; | ||||
|         display: inline-flex; | ||||
|         transform: skewX(-8deg); | ||||
|         background: linear-gradient(to bottom, '#ff7e5f', '#548fff'); | ||||
|         -webkit-background-clip: text; | ||||
|         letter-spacing: 1px; | ||||
|         color: #fff; | ||||
|         text-shadow: -2px 0 0 1px #add8f1; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .code-pie { | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
|     top: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,128 @@ | ||||
| <template> | ||||
|   <div class="demo detection-roll-list" 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 + ')' }"> | ||||
|                 <span v-if="b != 'status'"> | ||||
|                   {{ item[b] }} | ||||
|                 </span> | ||||
|                 <span v-else :class="item[b] == 0 ? 'status-no' : 'status-y'"> | ||||
|                   {{ item[b] == 0 ? '不合格' : '合格' }} | ||||
|                 </span> | ||||
|               </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: '红星农业合作社', agency: '耿马农残检测中心', time: '2025.01.02', status: 1, info: '经销商资质不合格' }, | ||||
|   { title: '成大食品加工厂', agency: '耿马农残检测中心', time: '2025.01.01', status: 1, info: '农药成分不合格' }, | ||||
|   { title: '大大食品加工厂', agency: '耿马食品检测中心', time: '2025.01.02', status: 0, info: '经销商资质不合格' }, | ||||
|   { title: '佳成农业合作社', agency: '耿马农残检测中心', time: '2025.01.01', status: 1, info: '成分不合格' }, | ||||
|   { title: '嘉庆食品加工厂', agency: '耿马食品检测中心', time: '2025.01.02', status: 1, info: '经销商资质不合格' }, | ||||
|   { title: '汇星农业合作社', agency: '耿马农残检测中心', time: '2025.01.01', status: 1, info: '经销商资质不完全' }, | ||||
|   { title: '瑞达农业合作社', agency: '耿马农残检测中心', time: '2025.01.02', status: 1, info: '种源质量不好' }, | ||||
| ]); | ||||
| 
 | ||||
| const listKeys = reactive(['title', 'agency', 'status']); | ||||
| const listKeysHeader = reactive({ | ||||
|   title: '送检单位', | ||||
|   agency: '检测单位', | ||||
|   status: '检测结果', | ||||
| }); | ||||
| 
 | ||||
| const classOptions = { | ||||
|   singleHeight: 48, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style scoped lang="scss"> | ||||
| .detection-roll-list { | ||||
|   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: 6px 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; | ||||
| 
 | ||||
|       .status-no { | ||||
|         color: red; | ||||
|       } | ||||
|       .status-y { | ||||
|         color: #6beff9; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .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> | ||||
| @ -0,0 +1,332 @@ | ||||
| <template> | ||||
|   <div class="main-part-charts"> | ||||
|     <div class="code-num-txt" :style="{ 'background-image': 'url(' + getAssetsFile('images/trace/bg2.png') + ')' }"> | ||||
|       <div class="num-txt-pos"> | ||||
|         <template v-for="(n, index) in valData" :key="index"> | ||||
|           <div class="num-txt"> | ||||
|             <div class="label"> | ||||
|               <span>{{ n.name }}</span> | ||||
|             </div> | ||||
|             <div class="val"> | ||||
|               <span class="val-val">{{ n.value }}</span> | ||||
|               <span class="unit">{{ n.unit }}</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </template> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="code-pie"> | ||||
|       <custom-echart-pie-gauge :chart-data="chartsData.valData" height="100%" :option="chartsData.option" /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from 'vue'; | ||||
| import { isEmpty, getAssetsFile } from '@/utils'; | ||||
| let valData = reactive([ | ||||
|   { value: 356, name: '追溯主体', unit: '家' }, | ||||
|   { value: 25, name: '检测机构', unit: '家' }, | ||||
|   { value: 199, name: '生成溯源码', unit: '次' }, | ||||
| ]); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     backgroundColor: 'transparent', | ||||
|     title: { | ||||
|       zlevel: 0, | ||||
|       text: 806, | ||||
|       subtext: '设备管理', | ||||
|       top: '38%', | ||||
|       left: '80%', | ||||
|       textAlign: 'center', | ||||
|       textStyle: { | ||||
|         color: '#fff', | ||||
|         fontSize: 14, | ||||
|       }, | ||||
|       subtextStyle: { | ||||
|         fontSize: 10, | ||||
|         color: '#fff', | ||||
|       }, | ||||
|       show: false, | ||||
|     }, | ||||
|     color: [ | ||||
|       { | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { offset: 0, color: 'rgba(40, 218, 239, 1)' }, | ||||
|           { offset: 1, color: 'rgba(130, 249, 255, 0.8)' }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 1, | ||||
|         y2: 0, | ||||
|         colorStops: [ | ||||
|           { offset: 0, color: 'rgba(198, 201, 24, 1)' }, | ||||
|           { offset: 1, color: 'rgba(198, 201, 24, 0.8)' }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 1, | ||||
|         y: 1, | ||||
|         x2: 0, | ||||
|         y2: 0, | ||||
|         colorStops: [ | ||||
|           { offset: 0, color: 'rgba(83, 165, 23, 1)' }, | ||||
|           { offset: 1, color: 'rgba(83, 165, 23, 0.8)' }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 1, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { | ||||
|             offset: 0, | ||||
|             color: 'rgba(75, 238, 114, 0.2)', // 0% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 1, | ||||
|             color: 'rgba(75, 238, 114, 1)', // 100% 处的颜色 | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|       { | ||||
|         x: 0, | ||||
|         y: 0, | ||||
|         x2: 0, | ||||
|         y2: 1, | ||||
|         colorStops: [ | ||||
|           { | ||||
|             offset: 0, | ||||
|             color: 'rgba(255, 19, 0, 0.2)', // 0% 处的颜色 | ||||
|           }, | ||||
|           { | ||||
|             offset: 1, | ||||
|             color: 'rgba(251, 95, 79, 1)', // 100% 处的颜色 | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { | ||||
|       type: 'pie', | ||||
|       name: '外层细圆环', | ||||
|       radius: ['58%', '60%'], | ||||
|       center: ['20%', '50%'], | ||||
|       hoverAnimation: true, | ||||
|       startAngle: 0, | ||||
|       clockWise: false, | ||||
|       itemStyle: { | ||||
|         normal: { | ||||
|           color: 'rgba(40, 218, 239, 0.8)', | ||||
|         }, | ||||
|       }, | ||||
|       label: { | ||||
|         show: false, | ||||
|       }, | ||||
|       data: [10], | ||||
|     }, | ||||
|     { | ||||
|       type: 'pie', | ||||
|       name: '内层细圆环', | ||||
|       radius: ['38%', '40%'], | ||||
|       center: ['20%', '50%'], | ||||
|       hoverAnimation: true, | ||||
|       startAngle: 0, | ||||
|       clockWise: false, | ||||
|       itemStyle: { | ||||
|         normal: { | ||||
|           color: 'rgba(40, 218, 239, 0.5)', | ||||
|         }, | ||||
|       }, | ||||
|       label: { | ||||
|         show: false, | ||||
|       }, | ||||
|       data: [10], | ||||
|     }, | ||||
|     { | ||||
|       name: '', | ||||
|       type: 'pie', | ||||
|       startAngle: 0, | ||||
|       radius: 70, | ||||
|       clockWise: false, | ||||
|       hoverAnimation: false, | ||||
|       center: ['20%', '50%'], | ||||
|       itemStyle: { | ||||
|         normal: { | ||||
|           labelLine: { | ||||
|             show: false, | ||||
|           }, | ||||
|           color: { | ||||
|             type: 'radial', | ||||
|             x: 0.5, | ||||
|             y: 0.5, | ||||
|             r: 0.5, | ||||
|             colorStops: [ | ||||
|               { offset: 1, color: 'rgba(129, 197, 200, 0.1)' }, | ||||
|               { offset: 0, color: 'rgba(129, 197, 200, 0)' }, | ||||
|             ], | ||||
|             globalCoord: false, | ||||
|           }, | ||||
|           shadowBlur: 10, | ||||
|         }, | ||||
|       }, | ||||
|       data: [ | ||||
|         { | ||||
|           value: 100, | ||||
|         }, | ||||
|       ], | ||||
|     }, | ||||
|     //环形 | ||||
|     { | ||||
|       name: '', | ||||
|       type: 'pie', | ||||
|       clockwise: false, | ||||
|       startAngle: -90, | ||||
|       radius: ['45%', '55%'], | ||||
|       center: ['20%', '50%'], | ||||
|       hoverAnimation: false, | ||||
|       label: { | ||||
|         normal: { | ||||
|           show: false, | ||||
|         }, | ||||
|         emphasis: { | ||||
|           show: false, | ||||
|         }, | ||||
|       }, | ||||
|       zlevel: 1, | ||||
|       labelLine: { | ||||
|         normal: { | ||||
|           show: false, | ||||
|         }, | ||||
|       }, | ||||
|       data: valData, | ||||
|     }, | ||||
|     //环形分割线 | ||||
|     { | ||||
|       name: '分割线', | ||||
|       type: 'gauge', | ||||
|       radius: '75%', | ||||
|       center: ['20%', '50%'], | ||||
|       clockwise: true, | ||||
|       startAngle: 90, // 起始角度 | ||||
|       endAngle: -360, // 结束角度 | ||||
|       splitNumber: 50, // 分割线数量 | ||||
|       zlevel: 2, | ||||
|       detail: { | ||||
|         offsetCenter: [10, 20], | ||||
|         formatter: ' ', | ||||
|       }, | ||||
|       axisLine: { | ||||
|         show: false, // 隐藏轴线 | ||||
|       }, | ||||
|       axisTick: { | ||||
|         show: false, // 隐藏刻度 | ||||
|       }, | ||||
|       splitLine: { | ||||
|         show: true, | ||||
|         length: 10, // 分割线的长度 | ||||
|         lineStyle: { | ||||
|           color: '#1e4960', | ||||
|           width: 1, // 分割线的宽度 | ||||
|         }, | ||||
|       }, | ||||
|       axisLabel: { | ||||
|         show: false, // 隐藏标签 | ||||
|       }, | ||||
|     }, | ||||
|   ], | ||||
| }); | ||||
| 
 | ||||
| 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> | ||||
| div { | ||||
|   box-sizing: border-box; | ||||
| } | ||||
| .main-part-charts { | ||||
|   height: 100%; | ||||
| 
 | ||||
|   position: relative; | ||||
|   .code-num-txt { | ||||
|     position: absolute; | ||||
|     right: 0; | ||||
|     top: 50%; | ||||
|     width: 80%; | ||||
|     transform: translateY(-50%); | ||||
|     background-size: contain; | ||||
|     background-repeat: no-repeat; | ||||
|     background-position: left center; | ||||
|     height: 100%; | ||||
|     padding: 10% 0 10% 18%; | ||||
|     .num-txt-pos { | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|       display: inline-flex; | ||||
|       justify-content: center; | ||||
|       flex-direction: column; | ||||
|     } | ||||
|     .num-txt { | ||||
|       width: 72%; | ||||
|       display: inline-flex; | ||||
|       justify-content: space-between; | ||||
|       padding: 0 16px; | ||||
|       line-height: 30px; | ||||
|       .val, | ||||
|       .label { | ||||
|         vertical-align: middle; | ||||
|         display: inline-flex; | ||||
|       } | ||||
|       .val { | ||||
|         .val-val { | ||||
|           font-size: 18px; | ||||
|           font-weight: bold; | ||||
|           display: inline-flex; | ||||
|           background: linear-gradient(360deg, #34c7d1, #fff); /* 渐变颜色 */ | ||||
|           -webkit-background-clip: text; /* 裁剪背景为文字形状 */ | ||||
|           background-clip: text; | ||||
|           letter-spacing: -1px; | ||||
|           -webkit-text-fill-color: transparent; /* 设置文字颜色为透明 */ | ||||
|         } | ||||
|       } | ||||
|       .label { | ||||
|         font-size: 12px; | ||||
|         font-weight: bold; | ||||
|         display: inline-flex; | ||||
|         transform: skewX(-8deg); | ||||
|         background: linear-gradient(to bottom, '#ff7e5f', '#548fff'); | ||||
|         -webkit-background-clip: text; | ||||
|         letter-spacing: 1px; | ||||
|         color: #fff; | ||||
|         text-shadow: -2px 0 0 1px #add8f1; | ||||
|       } | ||||
| 
 | ||||
|       .unit { | ||||
|         font-size: 8px; | ||||
|         color: #34c7d1; | ||||
|         padding: 6px 0 0 6px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   .code-pie { | ||||
|     position: absolute; | ||||
|     right: left; | ||||
|     top: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,72 @@ | ||||
| <template> | ||||
|   <div class="principal-type-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: ['#5cd2db', '#e4f116', '#6af116', '#2bb0ef'], | ||||
|     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: ['50%', '65%'], | ||||
|         // roseType: 'area', | ||||
|         center: ['40%', '50%'], | ||||
|         label: { | ||||
|           show: false, | ||||
|         }, | ||||
|         itemStyle: { | ||||
|           borderRadius: 5, | ||||
|         }, | ||||
|         // animationDuration: 15000, | ||||
|         // // 可选:设置动画缓动效果 | ||||
|         // animationEasing: 'elasticOut', | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { value: 37, name: '种源企业' }, | ||||
|     { value: 135, name: '农企/合作社' }, | ||||
|     { value: 41, name: '农资企业' }, | ||||
|     { value: 141, 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> | ||||
| .principal-type-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,74 @@ | ||||
| <template> | ||||
|   <div class="product-type-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: ['#5cd2db', '#e4f116', '#6af116', '#2bb0ef', '#a56aef', '#efb56a'], | ||||
|     title: { | ||||
|       text: ' ', | ||||
|       textStyle: { | ||||
|         color: '#333', | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       data: ['农副产品加工', '水果', '蔬菜', '水产', '禽畜肉蛋', '米面粮油'], | ||||
|       right: '0', // 距离左侧10%的位置 | ||||
|       top: 'middle', // 垂直居中 | ||||
|       orient: 'vertical', // 图例垂直排列 | ||||
|       itemWidth: 10, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     label: { | ||||
|       color: '#333', | ||||
|     }, | ||||
|     series: [ | ||||
|       { | ||||
|         type: 'pie', | ||||
|         radius: ['20%', '65%'], | ||||
|         roseType: 'area', | ||||
|         center: ['40%', '50%'], | ||||
|         label: { | ||||
|           show: false, | ||||
|         }, | ||||
|         itemStyle: { | ||||
|           borderRadius: 5, | ||||
|         }, | ||||
|         // animationDuration: 15000, | ||||
|         // // 可选:设置动画缓动效果 | ||||
|         // animationEasing: 'elasticOut', | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   valData: [ | ||||
|     { value: 37, name: '农副产品加工' }, | ||||
|     { value: 135, name: '水果' }, | ||||
|     { value: 41, name: '蔬菜' }, | ||||
|     { value: 141, name: '水产' }, | ||||
|     { value: 41, name: '禽畜肉蛋' }, | ||||
|     { value: 141, 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> | ||||
| .product-type-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -0,0 +1,131 @@ | ||||
| <template> | ||||
|   <div class="pathology-charts"> | ||||
|     <custom-echart-mixin :chart-data="handelData" :option="chartsData.option" height="100%" /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted, computed } from 'vue'; | ||||
| let itemStyle = reactive({ | ||||
|   itemStyle: { borderRadius: [8, 8, 0, 0] }, | ||||
| }); | ||||
| 
 | ||||
| let legendList = reactive(['溯源码']); | ||||
| const chartsData = reactive({ | ||||
|   option: { | ||||
|     color: ['#3685fe', '#41b879', '#ffd500', '#e57373'], | ||||
|     title: { | ||||
|       text: ' ', | ||||
|       textStyle: { | ||||
|         color: '#333', | ||||
|       }, | ||||
|     }, | ||||
|     legend: { | ||||
|       show: true, | ||||
|       data: legendList, | ||||
|       left: '0', // 距离左侧10%的位置 | ||||
|       top: '0', // 垂直居中 | ||||
|       itemWidth: 15, // 图例标记的宽度 | ||||
|       itemHeight: 8, // 图例标记的高度 | ||||
|       textStyle: { | ||||
|         fontSize: 10, // 图例文字的字体大小 | ||||
|         color: '#fff', // 图例文字的颜色 | ||||
|       }, | ||||
|     }, | ||||
|     barStyle: { | ||||
|       barWidth: 10, | ||||
|       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 | ||||
|       }, | ||||
|     }, | ||||
|     dataZoom: [ | ||||
|       // { | ||||
|       //   type: 'slider', // 滑动条型数据区域缩放组件 | ||||
|       //   startValue: 0, // 数据窗口起始值的索引 | ||||
|       //   endValue: 2, // 数据窗口结束值的索引 | ||||
|       // }, | ||||
|       // { | ||||
|       //   type: 'inside', // 支持鼠标滚轮和触控板缩放和平移 | ||||
|       //   startValue: 0, | ||||
|       //   endValue: 2, | ||||
|       // }, | ||||
|     ], | ||||
|     yAxis: [ | ||||
|       { | ||||
|         type: 'value', | ||||
|         name: ' ', | ||||
|         axisLabel: { | ||||
|           formatter: '{value}', | ||||
|         }, | ||||
|         splitLine: { | ||||
|           show: true, // 显示分割线 | ||||
|           lineStyle: { | ||||
|             type: 'dashed', // 设置为虚线 | ||||
|             width: 0.5, // 分割线宽度 | ||||
|           }, | ||||
|         }, | ||||
| 
 | ||||
|         itemStyle: { fontSize: 8 }, | ||||
|       }, | ||||
|     ], | ||||
|     grid: { | ||||
|       x: '10%', | ||||
|       x2: '10%', | ||||
|       y: '20%', | ||||
|       y2: '20%', | ||||
|     }, | ||||
|   }, | ||||
|   valData: [], | ||||
| }); | ||||
| 
 | ||||
| const randomVal = (num) => { | ||||
|   let list = []; | ||||
|   for (let i = 0; i < legendList.length; i++) { | ||||
|     let addNum = [10, 8, 2, 5]; | ||||
|     let val = { | ||||
|       name: num + '月', | ||||
|       value: Number(Math.random() * 100 + addNum[i]).toFixed(2), | ||||
|       seriesType: 'bar', | ||||
|       type: legendList[i], | ||||
|     }; | ||||
|     let lastVal = { | ||||
|       ...val, | ||||
|       ...itemStyle, | ||||
|     }; | ||||
|     list[i] = i < legendList.length - 1 ? val : lastVal; | ||||
|   } | ||||
|   return list; | ||||
| }; | ||||
| let handelData = computed(() => { | ||||
|   let list = []; | ||||
|   let maxMouth = 12; | ||||
|   for (let i = 0; i < maxMouth; i++) { | ||||
|     let val = randomVal(i + 1); | ||||
|     list = [...list, ...val]; | ||||
|   } | ||||
| 
 | ||||
|   list.map((m, indexm) => { | ||||
|     return { ...m, value: Number(Number(m.value) + Math.random() + indexm).toFixed(0) }; | ||||
|   }); | ||||
|   // console.info('handelData', list); | ||||
|   return list; | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => {}); | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .pathology-charts { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @ -4,15 +4,53 @@ | ||||
|       <template #center> | ||||
|         <el-row style="width: 100%; height: 100%"> | ||||
|           <el-col :span="6" class="left-charts"> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"></div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="溯源码数据统计" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <codeNumCharts></codeNumCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="追溯主体类型统计" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <principalTypeCharts></principalTypeCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="left-charts-item"> | ||||
|               <customBack top-title="追溯产品分类" :top-postion="'left'"> | ||||
|                 <template #back> | ||||
|                   <productTypeCharts></productTypeCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
|           <el-col :span="12"> | ||||
|             <centerMap></centerMap> | ||||
|           </el-col> | ||||
|           <el-col :span="12"></el-col> | ||||
|           <el-col :span="6" class="right-charts"> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"></div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="溯源主体信息统计" :top-postion="'right'"> | ||||
|                 <template #back> | ||||
|                   <mainPartCharts></mainPartCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="溯源码数据统计" :top-postion="'right'"> | ||||
|                 <template #back> | ||||
|                   <traceBarCharts></traceBarCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|             <div class="right-charts-item"> | ||||
|               <customBack top-title="最新溯源检测信息" :top-postion="'right'"> | ||||
|                 <template #back> | ||||
|                   <detectionCharts></detectionCharts> | ||||
|                 </template> | ||||
|               </customBack> | ||||
|             </div> | ||||
|           </el-col> | ||||
|         </el-row> | ||||
|       </template> | ||||
| @ -21,6 +59,14 @@ | ||||
| </template> | ||||
| <script setup> | ||||
| import baseBg from '@/components/baseBg.vue'; | ||||
| import customBack from '@/components/customBack.vue'; | ||||
| import centerMap from '@/components/centerMap.vue'; | ||||
| import codeNumCharts from './components/codeNumCharts.vue'; | ||||
| import mainPartCharts from './components/mainPartCharts.vue'; | ||||
| import principalTypeCharts from './components/principalTypeCharts.vue'; | ||||
| import productTypeCharts from './components/productTypeCharts.vue'; | ||||
| import traceBarCharts from './components/traceBarCharts.vue'; | ||||
| import detectionCharts from './components/detectionCharts.vue'; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .data-home-index { | ||||
|  | ||||