Compare commits

...

3 Commits

Author SHA1 Message Date
2090205686@qq.com
bea334086a 产出品管理页面调整(未完);小模块title和顶部菜单样式调整全局样式; 2025-05-14 17:28:42 +08:00
2090205686@qq.com
3330fed4e9 新版大屏调整,首页完,产出品管理未完 2025-05-12 23:39:08 +08:00
2090205686@qq.com
7c135ca70b 初始化项目配置 2025-05-12 11:28:09 +08:00
18 changed files with 23677 additions and 6953 deletions

2
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,2 @@
{
}

1
.yarnrc.yml Normal file
View File

@ -0,0 +1 @@
nodeLinker: node-modules

13213
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,8 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@smallwei/avue": "^3.6.2",
"@vuemap/vue-amap": "^2.0",
"@vuemap/vue-amap-loca": "^2.0",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"animate.css": "^4.1.1",
@ -25,8 +27,6 @@
"echarts-gl": "^2.0.9",
"echarts-liquidfill": "^3.1.0",
"echarts-wordcloud": "^2.1.0",
"@vuemap/vue-amap": "^2.0",
"@vuemap/vue-amap-loca": "^2.0",
"element-plus": "^2.7.2",
"js-base64": "^3.7.6",
"lodash": "^4.17.21",

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -36,10 +36,10 @@ export default {
const { setOptions, getInstance, resize, startAutoPlay } = useEcharts(chartRef);
const option = reactive({
tooltip: {
// trigger: 'axis',
// axisPointer: {
// type: 'shadow',
// },
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
backgroundColor: 'rgba(18, 55, 85, 0.8);',
borderColor: '#35d0c0',
formatter: (data) => {
@ -62,7 +62,7 @@ export default {
gap: 0,
label: {
show: true,
position: 'right',
position: 'outside',
width: '200px',
align: 'right',
formatter: function (params) {
@ -74,9 +74,29 @@ export default {
a: { color: '#fff', fontSize: '16px' },
b: { color: '#05FCC6', fontSize: '16px' },
},
verticalAlign: 'middle',
padding: [5, 10], //
},
labelLine: {
show: false,
show: true,
length: 20,
length2: 30,
smooth: true,
lineStyle: {
width: 2,
color: '#ffffff',
opacity: 1,
type: 'solid',
},
// 线
// idx-, params-
// formatter: function (idx, params) {
// return [
// [params.labelRect.x, params.labelRect.y], //
// [params.labelRect.x + 20, params.labelRect.y], // 线
// [params.labelRect.x + 20, params.dataCoord[1]] // 线
// ];
// },
},
itemStyle: {
show: false,

View File

@ -69,7 +69,7 @@ const props = defineProps({
});
const titleContentW = ref('0');
const itemW = ref('1');
const gap = ref(24);
const gap = ref(1);
const leftNum = ref(0);
const position = ref(0);
const right = ref(null);
@ -133,7 +133,7 @@ function handleTitleClick(val) {
.header_title {
background-color: #000;
position: relative;
padding: 0 68px;
padding: 0 40px;
display: flex;
justify-content: space-between;
width: 100vw;
@ -174,7 +174,7 @@ function handleTitleClick(val) {
.left_titles_container,
.right_titles_container {
position: relative;
width: 30%;
width: 31%;
height: 100%;
overflow: hidden;
line-height: 90px;
@ -182,10 +182,10 @@ function handleTitleClick(val) {
position: absolute;
top: 10px;
width: var(--titleContentW);
height: 40px;
height: 56px;
transition: all 0.4s ease;
font-size: 20px;
font-weight: bold;
font-size: 24px;
// font-weight: bold;
.active {
color: #fff;
opacity: 1 !important;
@ -194,9 +194,9 @@ function handleTitleClick(val) {
.title_item {
margin-right: var(--gap);
display: inline-block;
width: var(--itemW);
height: 40px;
line-height: 40px;
min-width: var(--itemW);
height: 56px;
line-height: 56px;
text-align: center;
color: #f5fffe;
cursor: pointer;

View File

@ -9,7 +9,7 @@
></div>
<span class="title-top-content" :style="{ 'text-align': props.left }">{{ topTitle || '--' }}</span>
<div v-if="isDown" class="down-list" :style="{ width: downWidth }">
<el-dropdown :hide-on-click="true" :style="{ width: '90%' }" trigger="click" @command="handleCommand">
<el-dropdown :hide-on-click="true" trigger="click" @command="handleCommand">
<span class="el-dropdown-link">
{{ currentVal && currentVal[labelField] ? currentVal[labelField] : downTitle }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
</span>
@ -147,8 +147,8 @@ const handleCommand = (data) => {
}
.title-top-content {
line-height: 38px;
font-size: 14px;
font-weight: bold;
font-size: 20px;
// font-weight: bold;
display: inline-block;
transform: skewX(-13deg);
background: linear-gradient(to bottom, '#ff7e5f', '#548fff');
@ -167,7 +167,7 @@ const handleCommand = (data) => {
.down-list {
display: inline-block;
position: absolute;
right: 32px;
right: 0;
top: 50%;
transform: translateY(-50%);
z-index: 2;
@ -178,6 +178,8 @@ const handleCommand = (data) => {
border: 1px solid $color-custom-main;
padding: 6px;
border-radius: 4px;
padding-left: 10px;
padding-right: 10px;
}
}
}

View File

@ -74,6 +74,7 @@ onMounted(() => {
}
.base-laytout-header {
height: 90px;
margin-bottom: 50px;
}
}
</style>

View File

@ -145,6 +145,7 @@ function handleChange(n) {
top: 8px;
width: 24px;
height: 24px;
text-shadow: 2px 0px 10px 0px #01eeff;
}
.left_btn {
left: 6px;

View File

@ -1,39 +1,60 @@
<template>
<customEchartHyalineCake :chart-data="data" height="100%" :option="option" />
<customEchartHyalineCake ref="chartRef" :chart-data="data" height="100%" :option="option" />
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { reactive, ref, onMounted } from 'vue';
const chartRef = ref(null);
/* --------------- data --------------- */
/* --------------- data右上侧饼图 --------------- */
// #region
const data = ref([
{
name: ' 企业',
value: 10.8,
itemStyle: { color: '#3c5fc4', opacity: 0.8 },
},
{
name: ' 合作社',
value: 8.4,
value: 18.4,
itemStyle: { color: '#8fd8ff', opacity: 0.8 },
},
{
name: ' 村集体',
value: 4.3,
value: 14.3,
itemStyle: { color: '#55d9a4', opacity: 0.8 },
},
{
name: ' 个体',
value: 3.7,
value: 23.7,
itemStyle: { color: '#d2a823', opacity: 0.8 },
},
]);
let itemGapWith = ref(0);
const getChartrefWith = () => {
let len = data.value.length * 2;
return chartRef.value.$refs.chartRef.offsetWidth / len + 8;
};
const option = reactive({
k: 0.2,
opacity: 0.6,
opacity: 0.4,
itemGap: 0,
autoItemHeight: 3,
legend: {
type: 'plain',
orient: 'horizontal',
width: '100%',
bottom: 10,
left: 'center',
itemWidth: 16,
itemHeight: 16,
itemGap: itemGapWith.value ? itemGapWith.value : 50,
textStyle: {
color: '#fff',
fontSize: '16px',
},
},
title: {
text: '23亿元',
@ -47,18 +68,18 @@ const option = reactive({
color: '#02FD94',
fontSize: '18px',
},
top: 'center',
top: '26%',
left: 'center',
},
grid3D: {
show: false,
boxHeight: 5,
top: 'center',
boxHeight: 3,
top: '-15%', //0
left: 'center',
viewControl: {
//3d
alpha: 30, //( )
distance: 160, //zoom()
alpha: 36, //( )
distance: 130, //zoom()
rotateSensitivity: 10, //0
zoomSensitivity: 10, //0
panSensitivity: 10, //0
@ -73,6 +94,10 @@ const option = reactive({
// #region
// #endregion
onMounted(() => {
itemGapWith.value = getChartrefWith();
option.legend.itemGap = itemGapWith.value ? itemGapWith.value : 50;
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,34 +1,21 @@
<template>
<custom-echart-line :chart-data="dataList" height="100%" :option="state.option" />
<custom-echart-line :chart-data="state.data" height="100%" :option="state.option" />
</template>
<script setup>
import { reactive } from 'vue';
let dataList = reactive([
{
value: 10,
name: '2020',
import { reactive, watch } from 'vue';
import { isEmpty, sleep } from '@/utils';
const props = defineProps({
data: {
type: Array,
default: () => [],
},
{
value: 66,
name: '2021',
query: {
type: String,
default: '',
},
{
value: 100,
name: '2022',
},
{
value: 120,
name: '2023',
},
{
value: 150,
name: '2024',
},
{
value: 80,
name: '2025',
},
]);
});
const state = reactive({
option: {
color: ['#35D0C0'],
@ -76,12 +63,12 @@ const state = reactive({
// name: '',
},
},
data: dataList,
data: [],
});
const refresData = () => {
console.info('landPatrol********************refresData');
state.data = dataList = reactive([
// console.info('landPatrol********************refresData');
state.data = reactive([
{
value: 20,
name: '2020',
@ -108,7 +95,53 @@ const refresData = () => {
},
]);
};
const loadData = async (code = '') => {
state.loading = true;
// GetInputsInfo()
// .then((res) => {
// if (res.code === 200) {
// state.data = res.data;
// }
// })
// .catch((err) => {
// app.$message.error(err.msg);
// });
await sleep(500);
state.data = [
{ value: 5, name: '2020' },
{ value: 36, name: '2021' },
{ value: 70, name: '2022' },
{ value: 56, name: '2023' },
{ value: 70, name: '2024' },
{ value: 20, name: '2025' },
];
};
watch(
() => props.data,
(val) => {
if (!isEmpty(val)) {
state.data = val;
}
},
{
deep: true,
immediate: true,
}
);
watch(
() => props.query,
(val) => {
if (!isEmpty(val)) {
loadData(val);
}
},
{
deep: true,
immediate: true,
}
);
defineExpose({
refresData,
});

View File

@ -2,21 +2,23 @@
<custom-echart-column-line :chart-data="state.data" height="100%" :option="state.option" />
</template>
<script setup>
import { reactive } from 'vue';
import { reactive, watch } from 'vue';
import { isEmpty, sleep } from '@/utils';
import * as echarts from 'echarts';
const props = defineProps({
data: {
type: Array,
default: () => [],
},
query: {
type: String,
default: '',
},
});
const state = reactive({
data: [
{ value: 103, value1: 208, name: '耿马镇' },
{ value: 72, value1: 157, name: '勐撒镇' },
{ value: 50, value1: 125, name: '勐永镇' },
{ value: 60, value1: 146, name: '孟定镇' },
{ value: 40, value1: 86, name: '勐简乡' },
{ value: 111, value1: 172, name: '贺派乡' },
{ value: 81, value1: 180, name: '四排山乡' },
{ value: 55, value1: 99, name: '芒洪乡' },
{ value: 68, value1: 84, name: '大兴乡' },
],
data: [],
option: {
grid: {
left: '3%',
@ -26,6 +28,7 @@ const state = reactive({
containLabel: true,
},
tooltip: {
show: true,
trigger: 'axis',
axisPointer: {
type: 'shadow',
@ -37,8 +40,8 @@ const state = reactive({
const params = data[0];
let str = `<div class="custom-echarts-tips">
<span>${params.name}</span><br/>
<span>${params.marker} ${params.data} </span><br />
<span>${data[1].marker} ${data[1].data} </span>
<span>${params.marker} ${params.data} </span><br />
<span>${data[1].marker} ${data[1].data} </span>
</div>`;
return str;
},
@ -199,4 +202,55 @@ const state = reactive({
],
},
});
const loadData = async (code = '') => {
state.loading = true;
// GetInputsInfo()
// .then((res) => {
// if (res.code === 200) {
// state.data = res.data;
// }
// })
// .catch((err) => {
// app.$message.error(err.msg);
// });
await sleep(500);
state.data = [
{ value: 103, value1: 208, name: '耿马镇' },
{ value: 72, value1: 157, name: '勐撒镇' },
{ value: 50, value1: 125, name: '勐永镇' },
{ value: 60, value1: 146, name: '孟定镇' },
{ value: 40, value1: 86, name: '勐简乡' },
{ value: 111, value1: 172, name: '贺派乡' },
{ value: 81, value1: 180, name: '四排山乡' },
{ value: 55, value1: 99, name: '芒洪乡' },
{ value: 68, value1: 84, name: '大兴乡' },
];
};
watch(
() => props.data,
(val) => {
if (!isEmpty(val)) {
state.data = val;
}
},
{
deep: true,
immediate: true,
}
);
watch(
() => props.query,
(val) => {
if (!isEmpty(val)) {
loadData(val);
}
},
{
deep: true,
immediate: true,
}
);
</script>

View File

@ -1,34 +1,40 @@
<template>
<customEchartHyalineCake :chart-data="data" height="100%" :option="option" />
<customEchartHyalineCake :chart-data="dataList" height="100%" :option="option" />
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
/* --------------- data --------------- */
/* --------------- 左中饼图 --------------- */
// #region
const data = ref([
const dataList = ref([
{
name: '烟草',
value: 60.8,
money: 100,
},
{
name: '甘蔗',
value: 44.4,
money: 88,
},
{
name: '核桃',
value: 24.3,
money: 92,
},
{
name: '蔬菜',
value: 32.7,
money: 56,
},
{
name: '其他',
value: 32.9,
money: 18,
},
]);
const option = reactive({
k: 0.3,
opacity: 1,
@ -36,13 +42,13 @@ const option = reactive({
autoItemHeight: 2,
grid3D: {
show: false,
boxHeight: 5,
top: '0',
boxHeight: 4, //
top: '0', //
left: '-20%',
viewControl: {
//3d
alpha: 30, //( )
distance: 160, //zoom()
distance: 200, //zoom()
rotateSensitivity: 10, //0
zoomSensitivity: 10, //0
panSensitivity: 10, //0
@ -50,6 +56,41 @@ const option = reactive({
autoRotateAfterStill: 2, //, autoRotate
},
},
// series: [
// // 2D 线
// {
// type: 'pie',
// radius: ['30%', '70%'],
// center: ['40%', '50%'],
// startAngle: -40, // 3D
// clockwise: false,
// label: {
// show: true,
// position: 'outside',
// formatter: (params) => {
// console.log(params);
// return `{a|${params.data.name}}\n{b|${params.data.money}}`;
// },
// rich: {
// a: { color: '#ffffff' },
// b: { color: '#79F5AF' },
// },
// },
// labelLine: {
// show: true,
// length: 10,
// length2: 15,
// lineStyle: {
// color: '#ffffff',
// width: 1,
// },
// },
// data: dataList,
// itemStyle: {
// opacity: 1, // 线
// },
// },
// ],
});
// #endregion

View File

@ -1,5 +1,10 @@
<template>
<div ref="chartsWarp" class="hot-charts">
<section class="_top_btns">
<span class="left_btn" @click="handleChange(-1)"></span>
<span class="right_btn" @click="handleChange(1)"></span>
{{ current.info.name }}
</section>
<custom-echart-triangle :chart-data="data" height="100%" :option="option" />
</div>
</template>
@ -13,9 +18,72 @@ const data = ref([
]);
const option = reactive({});
onMounted(() => {});
const list = ref([
{
name: '茶叶',
value: '1',
},
{
name: '核桃',
value: '2',
},
{
name: '玉米',
value: '3',
},
]);
const current = reactive({
index: 0,
length: list.value.length - 1,
info: {
name: '茶叶',
value: '20',
},
});
function handleChange(n) {
if (current.index == 0 && n == -1) {
current.index = current.length;
} else if (current.index == current.length && n == 1) {
current.index = 0;
} else {
current.index += n;
}
current.info = list.value[current.index];
}
</script>
<style lang="scss" scoped>
.hot-charts {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
._top_btns {
position: relative;
height: 40px;
width: 30%;
font-size: 20px;
text-align: center;
color: #fff;
line-height: 40px;
background: url('../../../assets/images/basic/tagBG-small.png') no-repeat center center / cover;
span {
display: block;
position: absolute;
top: 8px;
width: 24px;
height: 24px;
text-shadow: 2px 0px 10px 0px #01eeff;
}
.left_btn {
left: -10px;
background: url('../../../assets/images/basic/leftArrowIcon.png') no-repeat center center / cover;
}
.right_btn {
right: -10px;
background: url('../../../assets/images/basic/rightArrowIcon.png') no-repeat center center / cover;
}
}
}
</style>

View File

@ -2,9 +2,29 @@
<el-row class="data-home-index">
<el-col :span="6" class="left-charts">
<div class="left-charts-item">
<customBack top-title="全县历年产值对比" :top-postion="'left'">
<customBack
top-title="全县历年产值对比"
:top-postion="'left'"
:down-title="'全县'"
:label-field="'label'"
:value-field="'value'"
:down-width="''"
:options="[
{ label: '全县', value: '530926' },
{ label: '耿马镇', value: '42611' },
{ label: '勐撒镇', value: '9259' },
{ label: '勐永镇', value: '17787' },
{ label: '孟定镇', value: '42610' },
{ label: '勐简乡', value: '17788' },
{ label: '贺派乡', value: '40161' },
{ label: '四排山乡', value: '40163' },
{ label: '大兴乡', value: '40159' },
]"
:is-down="true"
@command="handleCommand"
>
<template #back>
<entitiesCategoryCharts></entitiesCategoryCharts>
<entitiesCategoryCharts ref="oneRef" :data="state.data.one" :query="state.queryCode"></entitiesCategoryCharts>
</template>
</customBack>
</div>
@ -16,9 +36,25 @@
</customBack>
</div>
<div class="left-charts-item">
<customBack top-title="全县作物产量对比" :top-postion="'left'">
<customBack
top-title="全县作物产量对比"
:top-postion="'left'"
:down-title="'烟草'"
:label-field="'label'"
:value-field="'value'"
:down-width="''"
:options="[
{ label: '烟草', value: 1 },
{ label: '甘蔗', value: 2 },
{ label: '核桃', value: 3 },
{ label: '蔬菜', value: 4 },
{ label: '其他', value: 5 },
]"
:is-down="true"
@command="handleContrast"
>
<template #back>
<entitiesStatistics></entitiesStatistics>
<entitiesStatistics ref="thirdRef" :data="state.data.third" :query="state.contrastCode"></entitiesStatistics>
</template>
</customBack>
</div>
@ -52,6 +88,7 @@
</el-row>
</template>
<script setup>
import { nextTick, reactive, ref } from 'vue';
import centerMap from '@/components/centerMap.vue';
import categoryCharts from './components/categoryCharts.vue';
import entitieslist from './components/entitieslist.vue';
@ -60,6 +97,58 @@ import benefitCharts from './components/benefitCharts.vue';
import entitiesStatistics from './components/entitiesStatistics.vue';
import entitiesCategoryCharts from './components/entitiesCategoryCharts.vue';
import entitiesMap from './components/entitiesMap.vue';
import { sleep } from '@/utils';
const oneRef = ref(null);
const thirdRef = ref(null);
const state = reactive({
loading: false,
data: {},
queryCode: '',
contrastCode: '',
});
const loadData = async () => {
state.loading = true;
await sleep(500);
state.data = {
one: [
{ value: 5, name: '2020' },
{ value: 36, name: '2021' },
{ value: 70, name: '2022' },
{ value: 56, name: '2023' },
{ value: 70, name: '2024' },
{ value: 20, name: '2025' },
],
third: [
{ value: 78, value1: 128, name: '耿马镇' },
{ value: 55, value1: 117, name: '勐撒镇' },
{ value: 65, value1: 145, name: '勐永镇' },
{ value: 60, value1: 126, name: '孟定镇' },
{ value: 40, value1: 86, name: '勐简乡' },
{ value: 81, value1: 152, name: '贺派乡' },
{ value: 41, value1: 130, name: '四排山乡' },
{ value: 63, value1: 109, name: '芒洪乡' },
{ value: 79, value1: 184, name: '大兴乡' },
],
};
};
loadData();
const handleCommand = (data) => {
state.queryCode = data.value;
// console.info('data=', data);
// nextTick(() => {
// oneRef.value && oneRef.value.refresData();
// });
};
const handleContrast = (data) => {
state.contrastCode = data.value;
// console.info('data=', data);
nextTick(() => {
thirdRef.value && thirdRef.value.refresData();
});
};
</script>
<style lang="scss" scoped>
.data-home-index {

View File

@ -2,8 +2,8 @@
<div class="data-home-index">
<template v-for="(n, index) in homeList" :key="n.name">
<div class="home-enter-item" :style="n.style" @click="itemClick(index)">
<div class="name">
<span>{{ n.title || '--' }}</span>
<div class="name" :style="n.nameStyle">
<span :style="n.spanStyle">{{ n.title || '--' }}</span>
</div>
<div class="img-icon" :style="n.imgstyle"><img :src="getAssetsFile(n.img)" /></div>
</div>
@ -32,17 +32,21 @@ let homeList = reactive([
linkType: 0,
url: '',
img: 'images/vsualized/home1.png',
style: 'left: 20%;bottom:320px;',
style: 'left: 21%;bottom:300px;',
imgstyle: 'width:100px;height:100px',
nameStyle: 'padding: 0 16px;margin: 16px 0;',
spanStyle: 'font-size: 20px;',
},
{
title: '农业产业运营服务平台',
title: '产业运营平台',
name: 'operation',
linkType: 0,
url: '',
img: 'images/vsualized/home2.png',
style: 'left: 20%;bottom: 64px;',
style: 'left: 22%;bottom: 24px;',
imgstyle: 'width:160px;height:160px',
nameStyle: 'padding: 0 22px;margin: 24px 0;border-radius: 16px;',
spanStyle: 'font-size: 28px;line-height: 66px',
},
{
title: '数字大屏',
@ -50,17 +54,21 @@ let homeList = reactive([
linkType: 1,
url: '/v2/land',
img: 'images/vsualized/home3.png',
style: 'right: 20%;bottom:320px;',
style: 'right: 23%;bottom:300px;',
imgstyle: 'width:100px;height:100px',
nameStyle: 'padding: 0 16px;margin: 16px 0;',
spanStyle: 'font-size: 20px;',
},
{
title: '农业产业政务服务平台',
title: '政务云平台',
name: 'gov',
linkType: 0,
url: '',
img: 'images/vsualized/home4.png',
style: 'right: 20%;bottom: 64px;',
style: 'right: 24%;bottom: 24px;',
imgstyle: 'width:160px;height:160px',
nameStyle: 'padding: 0 22px;margin: 24px 0;border-radius: 16px;',
spanStyle: 'font-size: 28px;line-height: 66px',
},
// ...
]);
@ -106,17 +114,24 @@ const itemClick = (index) => {
.name {
color: #fff;
font-family: 'JinBuTi';
margin: 24px 0;
background: linear-gradient(180deg, #01fefd, rgba(1, 254, 253, 0));
border: 2px solid #01fefd;
border-radius: 8px;
padding: 0 24px;
span {
backdrop-filter: blur(8px);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(180deg, #01fefd, rgba(1, 254, 253, 0));
opacity: 0.16; //
z-index: -1; //
border-radius: 6px; //
}
span {
line-height: 40px;
text-shadow: 0px 4px 8px 0px #01fefd;
font-size: 28px;
}
}
.img-icon {

16857
yarn.lock

File diff suppressed because it is too large Load Diff