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 {
|
||||
|