This commit is contained in:
lzc 2025-03-24 17:33:01 +08:00
commit c24569747e
18 changed files with 1133 additions and 224 deletions

View File

@ -0,0 +1,92 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script>
import { ref, reactive, watchEffect } from 'vue';
import { cloneDeep } from 'lodash';
import { useEcharts } from '../../hooks/useEcharts';
export default {
name: 'CustomEchartRadar',
props: {
chartData: {
type: Array,
default: () => [],
required: true,
},
option: {
type: Object,
default: () => ({}),
},
type: {
type: String,
default: 'radar',
},
width: {
type: String,
default: '100%',
},
height: {
type: String,
default: 'calc(100vh - 78px)',
},
},
emits: ['click'],
setup(props, { emit }) {
const chartRef = ref(null);
const { setOptions, getInstance } = useEcharts(chartRef);
const option = reactive({
title: {
text: '',
},
legend: {},
radar: {},
tooltip: {},
series: [
{
type: 'radar',
data: [],
},
],
});
watchEffect(() => {
props.chartData && initCharts();
});
function initCharts() {
if (props.option) {
Object.assign(option, cloneDeep(props.option));
}
let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
let indicator = Array.from(
new Set(
props.chartData.map((item) => {
let { name, max } = item;
return { name, max };
})
)
);
let data = [];
typeArr.forEach((type) => {
const radarStyle = props.option?.radarStyle ?? {};
let obj = { name: type, ...radarStyle };
let chartArr = props.chartData.filter((item) => type === item.type);
obj['value'] = chartArr.map((item) => item.value);
data.push(obj);
});
option.radar.indicator = indicator;
option.series[0]['data'] = data;
setOptions(option);
getInstance()?.off('click', onClick);
getInstance()?.on('click', onClick);
}
function onClick(params) {
emit('click', params);
}
return { chartRef };
},
};
</script>

View File

@ -1,25 +1,34 @@
<template>
<div :class="`custom-table-tree ${shadow ? 'custom-table-tree__shadow' : ''}`">
<div v-if="title" class="title">{{ title }}</div>
<el-tree
:data="data"
:node-key="option.nodeKey"
:show-checkbox="option.showCheckbox"
:default-expanded-keys="option.defaultExpandedKeys"
:default-checked-keys="option.defaultCheckedKeys"
:props="option.props ?? option.defaultProps"
@node-click="handleNodeClick"
>
<template #default="{ data: rows }">
<slot :data="rows"></slot>
</template>
</el-tree>
<div class="panel">
<el-input v-if="filter" v-model="state.keyword" clearable placeholder="请输入关键字筛选" class="panel-filter" />
<el-tree
ref="treeRef"
:data="state.list"
:node-key="option.nodeKey"
:show-checkbox="option.showCheckbox"
:default-expanded-keys="option.defaultExpandedKeys"
:default-checked-keys="option.defaultCheckedKeys"
:default-expand-all="option.defaultExpandAll"
:props="option.props ?? option.defaultProps"
:filter-node-method="filterNodeMethod"
@node-click="handleNodeClick"
>
<template #default="{ data: rows }">
<slot :data="rows"></slot>
</template>
</el-tree>
</div>
</div>
</template>
<script setup name="custom-table-tree">
import { reactive, ref, watch } from 'vue';
const props = defineProps({
title: { type: String, default: '' },
shadow: { type: Boolean, default: true },
filter: { type: Boolean, default: false },
data: { type: Array, default: () => [] },
option: {
type: Object,
@ -34,12 +43,42 @@ const props = defineProps({
},
defaultExpandedKeys: [],
defaultCheckedKeys: [],
defaultExpandAll: false,
};
},
},
});
const emit = defineEmits(['node-click']);
const treeRef = ref(null);
const state = reactive({
keyword: '',
list: [],
});
const label = props.option.props?.label ?? 'label';
watch(
() => props.data,
(val) => {
state.list = val;
},
{
immediate: true,
}
);
watch(
() => state.keyword,
(val) => {
treeRef.value.filter(val);
}
);
const filterNodeMethod = (value, data) => {
if (!value) return true;
return data[label].includes(value);
};
const handleNodeClick = (data, node) => {
emit('node-click', data, node);
};
@ -48,6 +87,7 @@ const handleNodeClick = (data, node) => {
.custom-table-tree {
width: 100%;
height: 100%;
min-height: 400px;
min-width: 200px;
@include flex-column();
@ -65,8 +105,15 @@ const handleNodeClick = (data, node) => {
background: var(--el-color-primary);
}
.el-tree {
.panel {
padding: 16px 10px 10px;
&-filter {
margin-bottom: 10px;
}
}
.el-tree {
box-sizing: border-box;
}
}

View File

@ -8,6 +8,7 @@ import CustomRichEditor from './custom-rich-editor';
import CustomEchartBar from './custom-echart-bar';
import CustomEchartPie from './custom-echart-pie';
import CustomEchartLine from './custom-echart-line';
import CustomEchartRadar from './custom-echart-radar';
import CustomEchartMixin from './custom-echart-mixin';
import customEchartPictorialBar from './custom-echart-pictorial-bar';
import CustomEchartLineLine from './custom-echart-line-line';
@ -26,6 +27,7 @@ export {
CustomEchartBar,
CustomEchartPie,
CustomEchartLine,
CustomEchartRadar,
CustomEchartMixin,
customEchartPictorialBar,
CustomEchartLineLine,

View File

@ -1,13 +1,13 @@
import request from '@/utils/axios';
export function getQuestionList(params) {
return request('/input/knowledge/page', {
return request('/inputGoods/knowledge/page', {
params,
});
}
export function getQuestionReply(data) {
return request('/input/knowledge/reply', {
return request('/inputGoods/knowledge/reply', {
data,
method: 'PUT',
});

View File

@ -2,14 +2,14 @@ import request from '@/utils/axios';
/* 租赁列表 */
export function getLeaseSuperviseList(params) {
return request('/input/machineLease/page', {
return request('/inputGoods/machineLease/page', {
params,
});
}
/* 新增租赁 */
export function addLeaseSupervise(data) {
return request('/input/machineLease/save', {
return request('/inputGoods/machineLease/save', {
method: 'POST',
data,
});

View File

@ -2,7 +2,13 @@ import request from '@/utils/axios';
/* 获取物资类型 */
export function getMaterailTypes(params) {
return request('/input/common/getList', {
return request('/inputGoods/common/getList', {
params,
});
}
/* 获取农药列表 */
export function getPesticideList(params) {
return request('/inputGoods/pesticide/page', {
params,
});
}

View File

@ -15,12 +15,12 @@ const inputSuppliesRoutes = [
// component: () => import('@/views/inputSuppliesManage/inputDataView/index.vue'),
// meta: { title: '投入品资源一张图', icon: 'Document' },
// },
{
path: '/sub-government-affairs-service/materialManage',
name: 'materialManage',
component: () => import('@/views/inputSuppliesManage/materialManage/index.vue'),
meta: { title: '物资管理融合', icon: 'Document' },
},
// {
// path: '/sub-government-affairs-service/materialManage',
// name: 'materialManage',
// component: () => import('@/views/inputSuppliesManage/materialManage/index.vue'),
// meta: { title: '物资管理融合', icon: 'Document' },
// },
{
path: '/sub-government-affairs-service/material',
name: 'material',
@ -40,24 +40,24 @@ const inputSuppliesRoutes = [
component: () => import('@/views/inputSuppliesManage/material/fertilizer/index.vue'),
meta: { title: '肥料管理', icon: 'Document' },
},
{
path: '/sub-government-affairs-service/material/ratPoison',
name: 'input-supplies-ratPoison',
component: () => import('@/views/inputSuppliesManage/material/ratPoison/index.vue'),
meta: { title: '兽药管理', icon: 'Document' },
},
{
path: '/sub-government-affairs-service/material/farmMachinery',
name: 'input-supplies-farmMachinery',
component: () => import('@/views/inputSuppliesManage/material/farmMachinery/index.vue'),
meta: { title: '农机管理', icon: 'Document' },
},
{
path: '/sub-government-affairs-service/material/seed',
name: 'input-supplies-seed',
component: () => import('@/views/inputSuppliesManage/material/seed/index.vue'),
meta: { title: '种源管理', icon: 'Document' },
},
// {
// path: '/sub-government-affairs-service/material/ratPoison',
// name: 'input-supplies-ratPoison',
// component: () => import('@/views/inputSuppliesManage/material/ratPoison/index.vue'),
// meta: { title: '兽药管理', icon: 'Document' },
// },
// {
// path: '/sub-government-affairs-service/material/farmMachinery',
// name: 'input-supplies-farmMachinery',
// component: () => import('@/views/inputSuppliesManage/material/farmMachinery/index.vue'),
// meta: { title: '农机管理', icon: 'Document' },
// },
// {
// path: '/sub-government-affairs-service/material/seed',
// name: 'input-supplies-seed',
// component: () => import('@/views/inputSuppliesManage/material/seed/index.vue'),
// meta: { title: '种源管理', icon: 'Document' },
// },
],
},
// {

View File

@ -1,6 +1,464 @@
<template>
<div style="width: 100%; height: 100%">
<div></div>
<div v-loading="state.loading" class="statistic">
<el-row :gutter="16" style="margin-bottom: 20px">
<el-col :span="12">
<el-card shadow="hover" class="statistic-data">
<b class="statistic-title">综合数据统计</b>
<el-row :gutter="16" style="margin-top: 40px">
<el-col :span="8" class="text-center">
<p>农村人口</p>
<avue-count-up end="27.88" :decimals="2" class="text-primary" />
<em>万人</em>
</el-col>
<el-col :span="8" class="text-center">
<p>耕地面积</p>
<avue-count-up end="103.88" :decimals="2" class="text-warning" />
<em>万亩</em>
</el-col>
<el-col :span="8" class="text-center">
<p>农业总产值</p>
<avue-count-up end="92.88" :decimals="2" class="text-danger" />
<em>亿元</em>
</el-col>
<el-col :span="24" class="text-center" style="margin-top: 90px">
<p>品牌农产品销售情况</p>
<avue-count-up end="17.88" :decimals="2" class="text-success" />
<em>亿元</em>
</el-col>
</el-row>
</el-card>
</el-col>
<el-col :span="12">
<el-card shadow="hover">
<custom-echart-bar :chart-data="state.areaData" height="400px" :option="state.areaOption" />
</el-card>
</el-col>
</el-row>
<el-row :gutter="16" style="margin-bottom: 20px">
<el-col :span="12">
<el-card shadow="hover">
<custom-echart-bar :chart-data="state.breedingData" height="400px" :option="state.breedingOption" />
</el-card>
</el-col>
<el-col :span="12">
<el-card shadow="hover">
<custom-echart-radar :chart-data="state.inputsData" height="400px" :option="state.inputsOption" />
</el-card>
</el-col>
</el-row>
<el-row :gutter="16" style="margin-bottom: 20px">
<el-col :span="12">
<el-card shadow="hover">
<custom-echart-pie :chart-data="state.businessData" height="400px" :option="state.businessOption" />
</el-card>
</el-col>
<el-col :span="12">
<el-card shadow="hover">
<custom-echart-mixin :chart-data="state.codingData" :option="state.codingOption" height="400px" />
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup name="home"></script>
<script setup>
import { reactive } from 'vue';
import { useRouter } from 'vue-router';
import { useApp } from '@/hooks';
import { sleep } from '@/utils';
const router = useRouter();
const app = useApp();
const state = reactive({
areaOption: {
// color: ['#fed500'],
title: {
text: '土地分布数据统计',
textStyle: {
color: '#333',
},
},
xAxis: {
type: 'category',
name: '区域',
},
yAxis: {
type: 'value',
name: '亩',
},
tooltip: {
formatter: function (params) {
return `${params.name}${params.value}`;
},
},
barStyle: {
barWidth: 50,
showBackground: true,
itemStyle: {
borderRadius: 20,
},
},
},
areaData: [
{ value: 230, name: '耿马镇' },
{ value: 165, name: '勐永镇' },
{ value: 217, name: '勐撒镇' },
{ value: 200, name: '孟定镇' },
{ value: 305, name: '大兴乡' },
],
breedingOption: {
color: ['#41b879', '#fed500'],
title: {
text: '种养殖综合数据统计',
textStyle: {
color: '#333',
},
},
tooltip: {
formatter: (params) => {
const find = state.breedingData.find((item) => item.name === params.name);
return `${params.name}${params.value}${find.unit}`;
},
},
barStyle: {
barWidth: 50,
showBackground: true,
itemStyle: {
borderRadius: 20,
},
},
},
breedingData: [
{ value: 230, name: '种植面积', unit: '亩' },
{ value: 165, name: '养殖面积', unit: '亩' },
{ value: 217, name: '种植基地', unit: '个' },
{ value: 200, name: '养殖基地', unit: '个' },
],
inputsOption: {
color: ['#ffd500'],
title: {
text: '投入品数据统计',
textStyle: {
color: '#333',
},
},
legend: { show: false },
radar: {
indicator: [],
center: ['50%', '50%'],
radius: 140,
startAngle: 90,
splitNumber: 4,
shape: 'circle',
axisName: {
formatter: '{value}',
// formatter: (params) => {
// const find = state.inputsData.find((item) => item.name === params);
// return `${params}${find.value}${find.unit}`;
// },
color: '#333',
},
splitArea: {
areaStyle: {
color: ['#77EADF', '#26C3BE', '#64AFE9', '#428BD4'],
shadowColor: 'rgba(0, 0, 0, 0.2)',
shadowBlur: 10,
},
},
axisLine: {
lineStyle: {
color: 'rgba(211, 253, 250, 0.8)',
},
},
splitLine: {
lineStyle: {
color: 'rgba(211, 253, 250, 0.8)',
},
},
},
radarStyle: {
areaStyle: {},
},
tooltip: {
formatter: (params) => {
let str = params.marker + params.name + '<br/>';
state.inputsData.forEach((item) => {
str += item.name + '' + item.value + item.unit + '<br/>';
});
return str;
},
},
},
inputsData: [
{ value: 75, name: '农药使用', type: '投入品', max: 100, unit: '吨' },
{ value: 38, name: '农机使用', type: '投入品', max: 100, unit: '台' },
{ value: 74, name: '种源使用', type: '投入品', max: 100, unit: '万吨' },
{ value: 55, name: '兽药使用', type: '投入品', max: 100, unit: '千克' },
{ value: 65, name: '肥料使用', type: '投入品', max: 100, unit: '吨' },
],
businessOption: {
title: {
text: '经营主体分类统计',
textStyle: {
color: '#333',
},
},
legend: {
right: '0',
top: 'middle',
orient: 'vertical',
itemWidth: 10,
itemHeight: 10,
},
label: {
color: '#333',
// formatter: ({ data }) => {
// return data.name + '' + data.value;
// },
},
tooltip: {
formatter: (params) => {
return `${params.name}${params.value}`;
},
},
series: [
{
type: 'pie',
radius: [80, 140],
itemStyle: {
borderRadius: 10,
},
},
],
},
businessData: [
{ value: 28, name: '个体户' },
{ value: 358, name: '村集体' },
{ value: 217, name: '合作社' },
{ value: 128, name: '农资企业' },
{ value: 22, name: '种源企业' },
{ value: 41, name: '生产加工企业' },
],
codingOption: {
color: ['#41b879', '#ffd500'],
title: {
text: '溯源赋码扫码统计',
textStyle: {
color: '#333',
},
},
legend: {},
yAxis: {
type: 'value',
name: '次',
},
barStyle: {
barWidth: 50,
},
// tooltip: {
// formatter: (params) => {
// const arr = state.codingData.filter((item) => item.name === params.name);
// return `${params.name}<br/>
// ${arr[0].type}${arr[0].value}<br/>
// ${arr[1].type}${arr[1].value}`;
// },
// },
},
codingData: [
{
name: '一月',
value: 40,
type: '赋码',
seriesType: 'bar',
},
{
name: '一月',
value: 60,
type: '扫码',
seriesType: 'line',
},
{
name: '二月',
value: 100,
type: '赋码',
seriesType: 'bar',
},
{
name: '二月',
value: 120,
type: '扫码',
seriesType: 'line',
},
{
name: '三月',
value: 80,
type: '赋码',
seriesType: 'bar',
},
{
name: '三月',
value: 124,
type: '扫码',
seriesType: 'line',
},
{
name: '四月',
value: 200,
type: '赋码',
seriesType: 'bar',
},
{
name: '四月',
value: 220,
type: '扫码',
seriesType: 'line',
},
],
loading: false,
});
//
const loadData = async () => {
state.loading = true;
await sleep(500);
state.loading = false;
// 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();
</script>
<style lang="scss" scoped>
.statistic {
.el-card {
border: 0 !important;
border-radius: 16px !important;
}
&-title {
font-size: 19px;
font-weight: bold;
font-family: '黑体';
color: #333;
flex: 1;
}
&-data {
height: 440px;
font-size: 18px;
p {
margin-bottom: 30px;
}
span {
font-size: 30px;
font-weight: bolder;
}
em {
font-style: normal;
font-size: 14px;
margin-left: 5px;
}
}
&-display {
@include flex-column();
background-repeat: no-repeat;
background-position: right bottom;
dt {
@include flex-row();
align-items: center;
margin-bottom: 30px;
i {
display: inline-block;
width: 72px;
height: 72px;
margin-right: 20px;
}
span {
font-size: 18px;
font-weight: 400;
}
}
dd {
span {
font-size: 22px;
font-weight: 500;
color: #000000;
}
}
&.d1 {
dt span {
color: #ff4975;
}
}
&.d2 {
dt span {
color: #41b879;
}
}
&.d3 {
dt span {
color: #3685fe;
}
}
&.d4 {
dt span {
color: #6b66ff;
}
}
}
&-table {
@include flex-row();
align-items: center;
}
&-rank {
li {
@include flex-row();
align-items: center;
margin-top: 16px;
i {
width: 72px;
height: 72px;
margin-right: 20px;
}
span {
@include flex-column();
flex: 1;
font-size: 14px;
}
em {
font-style: normal;
color: #999;
}
}
}
}
</style>

View File

@ -0,0 +1,85 @@
<template>
<section class="custom_number_select_" style="">
<el-input-number v-model="data.num" :precision="2" :step="1" :min="1" controls-position="right" @change="handleChange"></el-input-number>
<el-select v-model="data.type" @change="handleChange">
<el-option v-for="item in props.options" :key="'custom_' + Date.now() + item.value" :label="item.label" :value="item.value" />
</el-select>
</section>
</template>
<script lang="ts" setup>
import { ref, watchEffect } from 'vue';
const emit = defineEmits(['update:value']);
const props = defineProps({
value: {
type: Object,
default: () => {
return {
num: 1,
type: '1',
};
},
},
options: {
type: Array,
default: () => [
{
value: '1',
label: 'value1',
},
{
value: '2',
label: 'value2',
},
{
value: '3',
label: 'value3',
},
],
},
numberSet: {
type: Object,
default: () => {
return {};
},
},
});
const _numberSet = ref({
precision: 2,
setp: 1,
min: 1,
max: 100,
controlsPosition: 'right',
});
const data = ref({
num: 1,
type: '1',
});
watchEffect(() => {
data.value = Object.assign(data.value, props.value);
_numberSet.value = Object.assign(_numberSet.value, props.set);
});
function handleChange() {
emit('update:value', data.value);
}
</script>
<style lang="scss" scoped>
.custom_number_select_ {
display: grid;
grid-template-columns: 75% 25%;
::v-deep() {
.el-input-number {
width: 100%;
.el-input__wrapper {
border-radius: 4px 0 0 4px;
}
}
.el-select__wrapper {
border-radius: 0 4px 4px 0 !important;
border-left: none;
}
}
}
</style>

View File

@ -2,16 +2,15 @@
<el-sub-menu :index="types.value" :popper-offset="2">
<template #title>{{ types.label }}</template>
<template v-for="item in types.children" :key="`type_menu_${item.value}`">
<el-menu-item v-if="!item.children" :index="item.value">{{ item.label }}</el-menu-item>
<el-menu-item v-if="!item.children || !item.children.length" :index="item.value">{{ item.label }}</el-menu-item>
<SubMenu v-else :types="item" />
</template>
</el-sub-menu>
</template>
<script setup>
import { ref } from 'vue';
import SubMenu from './SubMenu.vue';
defineProps({
const props = defineProps({
types: {
type: Object,
default: () => {
@ -32,15 +31,6 @@ defineProps({
},
},
});
/* --------------- data --------------- */
// #region
// #endregion
/* --------------- methods --------------- */
// #region
// #endregion
</script>
<style lang="scss" scoped></style>

View File

@ -11,7 +11,7 @@
import SubMenu from './SubMenu.vue';
const emit = defineEmits(['update:type']);
defineProps({
const props = defineProps({
types: {
type: Array,
default: () => [

View File

@ -1,51 +1,103 @@
import { ref } from 'vue';
import { ref, onMounted, reactive } from 'vue';
import inputSuppliesApis from '@/apis/inputSuppliesApi';
const { getMaterailTypes } = inputSuppliesApis;
export function useBasicInfo(set = {}) {
const loadFinish = ref(false);
const searchCondition = Object.assign(
{
dataType: '',
moduleType: '',
},
set
);
/* ------ data ------ */
// #region
const materialTypes = reactive({
1: [{ value: '0', label: '全部' }],
2: [{ value: '0', label: '全部' }],
3: [{ value: '0', label: '全部' }],
4: [{ value: '0', label: '全部' }],
5: [{ value: '0', label: '全部' }],
});
const materialTwoLevel = ref({});
export function useBasicInfo() {
const pesticideData = ref([
{ label: '全部', value: '0' },
{
label: '防治对象',
value: '1',
children: [
{ label: '杀虫剂', value: '1-1' },
{ label: '除草剂', value: '1-2' },
{ label: '杀菌剂', value: '1-3' },
{ label: '杀螨剂', value: '1-4' },
{ label: '生物农药', value: '1-5' },
{ label: '植物生长调节剂', value: '1-6' },
],
},
{
label: '化学成分',
value: '2',
children: [
{ label: '无机农药', pid: '2', value: '2-1' },
{ label: '生物农药', pid: '2', value: '2-2' },
{
label: '有机农药',
pid: '2',
value: '2-3',
children: [
{ label: '天然有机农药', pid: '2-3', value: '2-3-1' },
{ label: '人工合成农药', pid: '2-3', value: '2-3-2' },
],
},
],
},
{
label: '加工剂型',
value: '3',
children: [
{ label: '可湿性粉剂', value: '3-1' },
{ label: '可溶性粉剂', value: '3-2' },
{ label: '乳剂', value: '3-3' },
{ label: '颗粒剂', value: '4-4' },
{ label: '缓释剂', value: '5-5' },
{ label: '烟剂', value: '6-6' },
],
},
/* ------ 农药 ------ */
// #region
const pesticideTypes = reactive({});
const goodsUnitOptions = reactive([
{ value: '1', label: 'ml/瓶' },
{ value: '2', label: 'mg/盒' },
{ value: '3', label: 'kg/袋' },
]);
const useDosageUnit = reactive([
{ value: '1', label: '/亩' },
{ value: '2', label: '/平方米' },
{ value: '3', label: '/株' },
]);
// #endregion
// #endregion
async function getmaterialType(_set = {}) {
let params = Object.assign(searchCondition, _set);
let res = await getMaterailTypes(params);
console.log('two --- ', res);
if (res && res?.code == 200) {
res.data.forEach((item) => {
const { moduleType, children } = item;
materialTypes[moduleType].push(...handleTypes(children));
handleTwoLevel();
});
}
loadFinish.value = true;
}
function handleTypes(arr) {
arr.forEach((item) => {
item.value = item.id;
item.label = item.dataName;
if (item.children.length > 0) {
item.children = handleTypes(item.children);
}
});
return arr;
}
function handleTwoLevel() {
for (let key in materialTypes) {
materialTwoLevel.value[key] = {};
materialTypes[key].forEach((v) => {
if (v.value != 0) {
materialTwoLevel.value[key][v.dataType] = v.children;
}
});
}
}
function filterTypes(_set = {}) {
let filterType = Object.assign(
{
dataType: '1',
moduleType: '1',
},
_set
);
let all = materialTypes[filterType.moduleType];
let _arr = [];
all.forEach((item) => {
console.log('item', item);
if (filterType.dataType == item.dataType) {
_arr = item.children;
}
});
return _arr;
}
onMounted(getmaterialType);
return {
pesticideData,
loadFinish,
materialTypes,
materialTwoLevel,
goodsUnitOptions,
useDosageUnit,
getmaterialType,
filterTypes,
};
}

View File

@ -1,7 +1,7 @@
<template>
<CustomCard>
<h2>农药基本信息</h2>
<TypeMenu v-model:type="_type" :types="pesticideData" />
<TypeMenu v-if="materialTypes.length > 1" v-model:type="_type" :types="materialTypes['1']" />
<br />
<avue-crud
ref="crud"
@ -10,6 +10,7 @@
:data="data"
:option="option"
:before-close="handleCloseDialog"
@refresh-change="getData"
@row-save="handleRowSave"
@row-update="handleRowUpdate"
>
@ -17,18 +18,23 @@
<el-button type="primary" @click="handleEdit(row)">上传报告</el-button>
<el-button @click="handleInfo(row)">详情</el-button>
</template>
<template #img-form="{ type }">
<Attrs v-model:attrs="img" :type="type == 'add' ? 'add' : 'view'" />
<template #photoUrl-form="{ type }">
<Attrs v-model:attrs="attrs" :type="type == 'add' ? 'add' : 'view'" />
</template>
<template #checkInfo-form="{ row }">
<section style="text-align: center; line-height: 58px">
{{ row }}
<el-button @click="handleCheckInfo('open')">查看报告</el-button>
</section>
</template>
<template #checkReport-form="{ type }">
<Attrs v-model:attrs="reportAttrs" :type="type" :up-btn="reportAttrs.length < 1" :file-num="reportAttrs.length > 0 ? 1 : 3" />
</template>
<template #productSpecification-form>
<NumberSelect v-model:value="productSpecification" :options="goodsUnitOptions" />
</template>
<template #dosage-form>
<NumberSelect v-model:value="useDosage" :options="useDosageUnit" />
</template>
<template #checkBtn-form>
<section style="text-align: center; line-height: 58px">
<el-button @click="handleCheckInfo('close')">关闭</el-button>
@ -39,14 +45,20 @@
</template>
<script setup>
import { reactive, ref, watch, h } from 'vue';
import { reactive, ref, watch, onMounted, h, computed } from 'vue';
import CustomCard from '@/components/CustomCard.vue';
import TypeMenu from '../../common/TypeMenu.vue';
import { CRUD_OPTIONS } from '@/config';
import { useBasicInfo } from '@/views/inputSuppliesManage/hooks/useBasicInfo';
import Attrs from '@/views/inputSuppliesManage/common/Attrs.vue';
import NumberSelect from '@/views/inputSuppliesManage/common/NumberSelect.vue';
import inputSuppliesApi from '@/apis/inputSuppliesApi';
const { pesticideData } = useBasicInfo();
const { loadFinish, materialTypes, materialTwoLevel, goodsUnitOptions, useDosageUnit, filterTypes } = useBasicInfo({
moduleType: '1',
});
const { getPesticideList } = inputSuppliesApi;
onMounted(getData);
/* --------------- data --------------- */
// #region
@ -60,51 +72,33 @@ watch(
deep: true,
}
);
const searchCondition = ref({
pesticideName: '',
});
const crud = ref();
const _loading = ref(false);
const data = ref([
{
name: '农药1',
id: '1111',
produicer: '生产商1',
dealer: '经销商1',
img: [
'https://gips0.baidu.com/it/u=3602773692,1512483864&fm=3028',
'https://gips3.baidu.com/it/u=100751361,1567855012&fm=3028',
'https://gips2.baidu.com/it/u=195724436,3554684702&fm=3028',
],
checkReport: [],
},
{
name: '农药2',
id: '2222',
produicer: '生产商2',
dealer: '经销商2',
img: ['https://gips3.baidu.com/it/u=100751361,1567855012&fm=3028'],
checkReport: ['https://gips3.baidu.com/it/u=100751361,1567855012&fm=3028'],
},
{
name: '农药3',
id: '3333',
produicer: '生产商3',
dealer: '经销商3',
img: [],
checkReport: [],
},
]);
const data = ref([]);
const pageData = ref({
total: 0,
currentPage: 1,
pageSize: 10,
size: 10,
});
const option = ref({
CRUD_OPTIONS,
...CRUD_OPTIONS,
selection: false,
labelWidth: 124,
editBtn: false,
delBtn: false,
menuWidth: 220,
dialogWidth: '60%',
column: [
{
hide: true,
label: '关键字',
search: true,
addDisplay: false,
editDisplay: false,
},
{
prop: 'id',
label: '农药编号',
@ -112,50 +106,55 @@ const option = ref({
editDisplay: false,
},
{
prop: 'name',
prop: 'pesticideName',
label: '名称',
editDisplay: false,
},
{
hide: true,
prop: 'code',
prop: 'productStandCode',
label: '产品标准证号',
viewDisplay: false,
editDisplay: false,
},
{
hide: true,
prop: 'img',
prop: 'photoUrl',
label: '农药图片',
editDisplay: false,
},
{
hide: true,
prop: 'code1',
prop: 'pesticideRegistCode',
label: '农药登记证号',
viewDisplay: false,
editDisplay: false,
},
{
prop: 'producer',
prop: 'manufacturer',
label: '生产厂家',
editDisplay: false,
},
{
prop: 'dealer',
prop: 'distributor',
label: '经销商',
editDisplay: false,
},
{
prop: 'format',
prop: 'productSpecification',
label: '产品规格',
editDisplay: false,
},
{
prop: 'toxicity',
prop: 'toxicityLevel',
label: '毒性',
editDisplay: false,
},
{
prop: 'dosage',
label: '建议用量',
editDisplay: false,
},
{
prop: 'validity',
label: '保质期',
@ -167,17 +166,17 @@ const option = ref({
type: 'cascader',
checkStrictly: true,
multiple: true,
dicData: pesticideData.value[1].children,
dicData: [],
span: 24,
editDisplay: false,
},
{
prop: 'chemicalComposition',
prop: 'mainComponents',
label: '化学成分',
type: 'cascader',
checkStrictly: true,
multiple: true,
dicData: pesticideData.value[2].children,
dicData: materialTwoLevel.value?.['1']?.['2'] ?? [],
span: 24,
editDisplay: false,
},
@ -187,7 +186,7 @@ const option = ref({
type: 'cascader',
checkStrictly: true,
multiple: true,
dicData: pesticideData.value[3].children,
dicData: materialTwoLevel.value?.['1']?.['3'] ?? [],
span: 24,
editDisplay: false,
},
@ -231,17 +230,17 @@ const option = ref({
editDisabled: true,
},
{
prop: 'producer',
prop: 'manufacturer',
label: '生产商',
editDisabled: true,
},
{
prop: 'img',
prop: 'photoUrl',
label: '农药图片',
editDisabled: true,
},
{
prop: 'dealer',
prop: 'distributor',
label: '经销商',
editDisabled: true,
},
@ -284,12 +283,56 @@ const option = ref({
},
],
});
const img = ref([]);
watch(
() => loadFinish.value,
() => {
if (loadFinish.value) {
let newDicName = [
{ key: '', one: '1', two: '1' },
{ key: '', one: '1', two: '2' },
{ key: '', one: '1', two: '3' },
];
newDicName.forEach((v) => {
option.value.column.forEach((item) => {
if (item.prop === v.key) {
item.dicData = materialTwoLevel?.[v.one]?.[v.two] ?? [];
}
});
});
}
}
);
const attrs = ref([]);
const reportAttrs = ref([]);
const productSpecification = ref({
num: 1,
type: '1',
});
const useDosage = ref({
num: 1,
type: '1',
});
// #endregion
/* --------------- methods --------------- */
// #region
async function getData(reset) {
_loading.value = true;
reset == 1 && (pageData.value.currentPage = 1);
let params = {
current: pageData.value.currentPage,
size: pageData.value.size,
...searchCondition.value,
};
let res = await getPesticideList(params);
console.log('res --- ', res);
_loading.value = false;
if (res && res.code === 200) {
data.value = res.data.records;
pageData.value.total = res.data.total;
}
}
function handleCloseDialog(done) {
handleCheckInfoChange();
done();
@ -302,7 +345,7 @@ function handleRowSave(form, done, loading) {
function handleEdit(row) {
console.log('handleEdit', row);
handleCheckInfoChange('open');
img.value = row.img.map((v) => {
attrs.value = row.map((v) => {
return {
url: v,
uid: Date.now(),
@ -336,7 +379,7 @@ function handleCheckInfoChange(bol = false) {
});
} else {
option.value.column.forEach((v) => {
if (!v.hide || v.prop == 'img') {
if (!v.hide || v.prop == 'photoUrl') {
v.viewDisplay = true;
}
});

View File

@ -1,5 +1,11 @@
<template>
<el-radio-group v-model="val" class="radio_group" style="margin-bottom: 30px" @change="emit('update:value', val)">
<el-radio-group
v-model="val"
class="radio_group"
style="margin-bottom: 30px"
:style="{ '--title-theme': val == '1' ? 'red' : 'black' }"
@change="emit('update:value', val)"
>
<el-radio-button v-for="item in options" :key="'radio_' + item.value" :value="item.value" color="red">
{{ item.label }}
</el-radio-button>
@ -65,20 +71,19 @@ const options = reactive([
}
.is-active {
.el-radio-button__inner {
background-color: unset !important;
background-color: var(--title-theme) !important;
color: #fff !important;
border-color: var(--title-theme) !important;
}
}
&:nth-child(1) {
.el-radio-button__inner {
background-color: red !important;
color: #fff;
border-color: red !important;
}
}
&:nth-child(2) {
.el-radio-button__inner {
color: rgba(28, 111, 255, 0.77) !important;
border-color: #c5c5c5 !important;
border-color: #c5c5c5;
}
}
}

View File

@ -1,13 +1,15 @@
<template>
<section class="rank_content" :style="{ '--theme': radio == '1' ? 'red' : 'black' }">
<h2>{{ type == '1' ? '企业' : '品牌' }}红黑榜</h2>
<br />
<RankType v-model:value="radio" />
<div class="rank_item rank_header">
<div class="index_">排名</div>
<div>企业名称</div>
<div>上榜理由</div>
<div>企业类型</div>
<div>{{ type == '1' ? '企业类型' : '所属品牌' }}</div>
</div>
<div v-for="(item, i) in radio == '1' ? props.data.red : props.data.black" :key="`rank_${props.type}_${i}`" class="rank_item">
<div v-for="(item, i) in radio == '1' ? data.red : data.black" :key="`rank_${type}_${i}`" class="rank_item">
<div class="index_">{{ i + 1 }}</div>
<div>{{ item.name }}</div>
<div>{{ item.reason }}</div>
@ -19,33 +21,36 @@
<script setup>
import { reactive, ref } from 'vue';
import RankType from './RankType.vue';
const props = defineProps({
defineProps({
type: {
type: String,
default: '1',
},
data: {
type: Object,
default: () => {
return {
red: [
{
name: '企业1',
reason: '企业1',
name: '惠民肥料公司',
reason: '物美价廉,对农民补贴力度大',
type: '生产商',
},
{
name: '企业2',
reason: '好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好好',
name: '新气象农机生产有限公司',
reason: '产品质量有保证,售后服务周到',
type: '生产商',
},
{
name: '企业3',
reason: '2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222',
name: '万好芽种公司',
reason: '种源质量可靠,相关培训指导完善',
type: '生产商',
},
],
black: [
{
name: '企业222',
reason: '不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好不好',
name: '欣欣肥料生产有限公司',
reason: '存在制假售假行为,目前正处于整改阶段',
type: '经销商',
},
],
@ -78,7 +83,7 @@ section {
font-size: 28px;
font-family: '黑体';
text-align: center;
color: var(--theme);
// color: var(--theme);
}
.rank_header {

View File

@ -1,8 +1,8 @@
<template>
<CustomCard>
<section class="rank_container">
<RankCard />
<RankCard />
<RankCard :data="data1" />
<RankCard :data="data2" type="2" />
</section>
</CustomCard>
</template>
@ -58,7 +58,123 @@ const redData = ref([
},
]);
const blackData = ref(JSON.parse(JSON.stringify(redData.value)));
const data1 = ref({
red: [
{
name: '惠民肥料公司',
reason: '物美价廉,对农民补贴力度大',
type: '生产商',
},
{
name: '新气象农机生产有限公司',
reason: '产品质量有保证,售后服务周到',
type: '生产商',
},
{
name: '中化化肥集团',
reason: '诚信经营',
type: '生产商',
},
{
name: '万好芽种公司',
reason: '货真价实',
type: '生产商',
},
{
name: '金正大复合肥',
reason: '诚信经营',
type: '经销商',
},
],
black: [
{
name: '欣欣肥料生产有限公司',
reason: '存在制假售假行为,目前正处于整改阶段',
type: '生产商',
},
{
name: '丰收之源化肥厂',
reason: '质量欠佳',
type: '生产商',
},
{
name: '肥效先锋农资店',
reason: '资质欠缺',
type: '经销商',
},
{
name: '四季农机专营店',
reason: '质量欠佳',
type: '经销商',
},
],
});
const data2 = ref({
red: [
{
name: '中化',
reason: '物美价廉,对农民补贴力度大',
type: '宋博农业',
},
{
name: '宜化',
reason: '产品质量有保证,售后服务周到',
type: '青岛迈高',
},
{
name: '金正大',
reason: '诚信经营',
type: '金正大',
},
{
name: '新洋丰',
reason: '货真价实',
type: '新洋丰',
},
{
name: '嘉施利',
reason: '诚信经营',
type: '麦得利',
},
{
name: '芭田生态',
reason: '产品质量有保证,售后服务周到',
type: '芭田生态',
},
{
name: '安牧歌',
reason: '诚信经营',
type: '蒙原牧场',
},
{
name: '今麦高',
reason: '货真价实',
type: '麦得利',
},
],
black: [
{
name: '得民农机',
reason: '质量欠佳',
type: '得名',
},
{
name: '麦洋洋',
reason: '存在制假售假行为,目前正处于整改阶段',
type: '阳光麦业',
},
{
name: '希沃',
reason: '资质欠缺',
type: '沣西',
},
{
name: '南丰',
reason: '质量欠佳',
type: '阿斯达',
},
],
});
// #endregion
/* --------------- methods --------------- */

View File

@ -38,9 +38,9 @@
</template>
</el-popconfirm>
</template>
<template #area-form="{ row, type }">
<section class="area_form_" style="">
<el-input-number v-model="landArea" :min="1" controls-position="right"></el-input-number>
<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>
<el-select v-model="unitValue">
<el-option v-for="item in unitOptions" :key="'unitOptions_' + item.value" :label="item.label" :value="item.value" />
</el-select>
@ -611,11 +611,11 @@ function newTree(arr, i) {
arr.forEach((v) => {
if (i == 0) {
v.value = v.id;
v.label = v.prentLandType;
v.label = v.landType;
v.disabled = !v.children || !v.children.length;
} else {
v.value = v.id;
v.label = v.childLandCategory;
v.label = v.landType;
}
if (v.children) v.children = newTree(v.children, i + 1);
});

View File

@ -2,7 +2,7 @@
<div class="custom-page">
<el-row :gutter="20">
<el-col :span="4">
<custom-table-tree title="种养殖基地分类" :data="landTypeData" @node-click="onNodeClick" />
<custom-table-tree title="种养殖基地分类" :data="treeData" @node-click="onNodeClick" />
</el-col>
<el-col :span="20">
<avue-crud
@ -24,7 +24,6 @@
@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>
@ -47,20 +46,21 @@ import { useRouter } from 'vue-router';
import { useApp } from '@/hooks';
import { useUserStore } from '@/store/modules/user';
import { CRUD_OPTIONS } from '@/config';
import { isEmpty, mockData, sleep } from '@/utils';
import { isEmpty, mockData, sleep, setDicData } from '@/utils';
import { getLandsList } from '@/apis/land';
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([
const treeData = ref([
{
label: '基地分类',
id: '0',
id: null,
children: [
{ label: '种植基地', id: '01', children: [], pId: '0' },
{ label: '养殖基地', id: '02', children: [], pId: '0' },
{ label: '种植基地', id: '1', children: [], pid: null },
{ label: '养殖基地', id: '2', children: [], pid: null },
],
},
]);
@ -114,38 +114,31 @@ const state = reactive({
label: '地块名',
prop: 'landName',
width: 200,
formslot: true,
type: 'select',
props: {
label: 'landName',
value: 'id',
},
dicUrl: `${VITE_APP_BASE_API}/land-resource/landManage/page?current=1&size=20`,
dicHeaders: {
authorization: UserStore.token,
},
dicFormatter: (res) => res.data?.records ?? [],
filterable: true,
remote: true,
clearable: true,
remoteMethod: (val) => remoteLandList(val),
change: (val) => selectedChange(val),
rules: {
required: true,
message: '请输入',
message: '请选择',
trigger: 'blur',
},
// addDisplay: true,
// editDisplay: true,
// viewDisplay: false,
// overHidden: true,
},
// {
// label: '',
// prop: 'p2',
// width: 200,
// type: 'select',
// // addDisplay: true,
// // editDisplay: true,
// // viewDisplay: false,
// // props: {
// // label: 'areaName',
// // value: 'areaCode',
// // children: 'areaChildVOS',
// // },
// // dicUrl: `${VITE_APP_BASE_API}/system/area/region?areaCode=530000`,
// // dicHeaders: {
// // authorization: UserStore.token,
// // },
// // dicFormatter: (res) => res.data ?? [],
// rules: {
// required: true,
// message: '',
// trigger: 'blur',
// },
// overHidden: true,
// },
{
label: '区域位置',
prop: 'p3',
@ -284,7 +277,7 @@ const loadData = async () => {
state.data = mockData(
{
p1: '耿马镇一号基地',
p2: '耿马镇2025001号地块',
landName: '耿马镇2025001号地块',
p3: '耿马傣族佤族自治县/耿马镇',
p4: '1000',
p5: '张三',
@ -418,4 +411,19 @@ const onDel = (rows = []) => {
const rowDel = (row, index, done) => {
onDel([row]);
};
//
const remoteLandList = async (val) => {
if (isEmpty(val)) return;
const query = { landName: val, current: 1, size: 20 };
const res = await getLandsList(query);
if (res.code === 200) {
setDicData(state.options.column, 'landName', res.data.records);
}
};
//
const selectedChange = ({ value, item }) => {
console.log(430, value, item, item.landName, item.address, item.area);
};
</script>