Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
3ac220221e
@ -13,9 +13,9 @@ VITE_APP_SUB_GSR = '//localhost:9530/new-digital-agriculture-screen/'
|
||||
VITE_APP_BASE_API = '/apis'
|
||||
VITE_APP_UPLOAD_API = '/uploadApis'
|
||||
# 阿里云接口地址
|
||||
# VITE_APP_BASE_URL = 'http://47.109.205.240:8080'
|
||||
# VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300'
|
||||
VITE_APP_BASE_URL = 'http://47.109.205.240:8080'
|
||||
VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9300'
|
||||
# 内网接口地址
|
||||
VITE_APP_BASE_URL = 'http://192.168.18.74:8080'
|
||||
# VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
|
||||
# VITE_APP_UPLOAD_URL = 'http://192.168.18.99:8080'
|
||||
# VITE_APP_VIST_URL = 'http://192.168.18.99'
|
||||
|
@ -12,7 +12,6 @@ declare module 'vue' {
|
||||
'CenterMap copy': typeof import('./src/components/centerMap copy.vue')['default']
|
||||
CodeDialog: typeof import('./src/components/code-dialog/index.vue')['default']
|
||||
Components: typeof import('./src/components/index.js')['default']
|
||||
copy: typeof import('./src/components/centerMap copy.vue')['default']
|
||||
CurrentTime: typeof import('./src/components/currentTime.vue')['default']
|
||||
CustomBack: typeof import('./src/components/customBack.vue')['default']
|
||||
CustomCarouselPicture: typeof import('./src/components/custom-carousel-picture/index.vue')['default']
|
||||
|
@ -9,11 +9,12 @@ VITE_APP_BASE_API = '/apis'
|
||||
VITE_APP_UPLOAD_API = '/uploadApis'
|
||||
|
||||
# 阿里云接口地址
|
||||
# VITE_APP_BASE_URL = 'http://47.109.205.240:8080'
|
||||
# VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9204'
|
||||
VITE_APP_BASE_URL = 'http://47.109.205.240:8080'
|
||||
VITE_APP_UPLOAD_URL = 'http://47.109.205.240:9204'
|
||||
|
||||
# 内网测试库接口地址
|
||||
VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
|
||||
# VITE_APP_BASE_URL = 'http://192.168.18.99:8080'
|
||||
# VITE_APP_UPLOAD_URL = 'http://192.168.18.99:8080'
|
||||
|
||||
# 本地开发接口地址
|
||||
# VITE_APP_BASE_URL = 'http://192.168.18.74:8080'
|
||||
|
@ -50,6 +50,7 @@ module.exports = {
|
||||
defineEmits: 'readonly',
|
||||
defineExpose: 'readonly',
|
||||
withDefaults: 'readonly',
|
||||
T: 'readonly',
|
||||
},
|
||||
// 这里时配置规则的,自己看情况配置
|
||||
rules: {
|
||||
|
@ -22,6 +22,7 @@
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.6.5",
|
||||
"echarts": "^5.6.0",
|
||||
"echarts-gl": "^2.0.9",
|
||||
"element-plus": "^2.7.2",
|
||||
"js-base64": "^3.7.6",
|
||||
"lodash": "^4.17.21",
|
||||
@ -33,7 +34,8 @@
|
||||
"screenfull": "^6.0.2",
|
||||
"splitpanes": "^4.0.3",
|
||||
"vue": "^3.3.11",
|
||||
"vue-router": "^4.2.5"
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-tianditu": "^2.7.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.7",
|
||||
|
@ -11,27 +11,35 @@ export function getMaterailTypes(params) {
|
||||
|
||||
/* 获取农药列表 */
|
||||
export function getPesticideList(params) {
|
||||
return request('/inputGoods/pesticide/page', {
|
||||
return request('/inputGoods/supervise/pesticide/page', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
/* 新增农药 */
|
||||
export function addPesticide(data) {
|
||||
return request('/inputGoods/pesticide/save', {
|
||||
return request('/inputGoods/supervise/pesticide/save', {
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
/* 农药检测报告 */
|
||||
/* 编辑农药 */
|
||||
export function pesticideReportSave(data) {
|
||||
return request('/inputGoods/pesticide/uploadReport', {
|
||||
return request('/inputGoods/supervise/pesticide/edit', {
|
||||
data,
|
||||
method: 'PUT',
|
||||
});
|
||||
}
|
||||
/* 删除农药 */
|
||||
export function delPesticide(ids) {
|
||||
return request(`/inputGoods/pesticide/delete/${ids}`);
|
||||
return request(`/inputGoods/supervise/pesticide/delete/${ids}`);
|
||||
}
|
||||
/* 获取用药地块下拉选项 */
|
||||
export function getLandList() {
|
||||
return request(`/inputGoods/supervise/pesticide/getLandList`);
|
||||
}
|
||||
/* 获取农药用药下拉选项 */
|
||||
export function getPesticideSelectList() {
|
||||
return request(`/inputGoods/pesticide/getPesticideList`);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
import request from '@/utils/axios';
|
||||
//新增备案信息(POST)
|
||||
export function createRecord(data) {
|
||||
return request({
|
||||
url: '/inputGoods/cropPlantRegistration/save',
|
||||
method: 'post',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
// 删除备案信息(DELETE)
|
||||
export function deleteRecord(id) {
|
||||
return request({
|
||||
url: `/inputGoods/cropPlantRegistration/delete/${id}`,
|
||||
method: 'delete',
|
||||
});
|
||||
}
|
||||
// 修改备案信息(PUT)
|
||||
export function updateRecord(data) {
|
||||
return request({
|
||||
url: `/inputGoods/cropPlantRegistration/uploadReport`,
|
||||
method: 'put',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
// 查询备案信息(GET)
|
||||
export function getRecord(id) {
|
||||
return request({
|
||||
url: `/inputGoods/cropPlantRegistration/get/${id}`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
// 查询备案信息列表(GET)
|
||||
export function fetchRecordList(params) {
|
||||
return request({
|
||||
url: '/inputGoods/cropPlantRegistration/page',
|
||||
method: 'get',
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
// 备案审核(PUT)
|
||||
export function auditRecord(data) {
|
||||
return request({
|
||||
url: `/inputGoods/cropPlantRegistration/approval`,
|
||||
method: 'put',
|
||||
data,
|
||||
});
|
||||
}
|
@ -68,3 +68,12 @@ export function getLandById(id) {
|
||||
params: { landId: id },
|
||||
});
|
||||
}
|
||||
|
||||
// 土地信息审批(PUT)
|
||||
export function approveLand(data) {
|
||||
return request({
|
||||
url: '/land-resource/approval/approval',
|
||||
method: 'POST',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
@ -15,3 +15,17 @@ export function GetLandData(params = {}) {
|
||||
params,
|
||||
});
|
||||
}
|
||||
//获取流转去未流转接口
|
||||
export function getOverview(params = {}) {
|
||||
return request('/land-resource/analysis/overview', {
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
//获取具体土地信息
|
||||
export function getSubArea(params = {}) {
|
||||
return request('/land-resource/analysis/subArea', {
|
||||
method: 'GET',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
@ -98,7 +98,14 @@ async function fetchGridList(regionCode) {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(fetchAreaData);
|
||||
onMounted(async () => {
|
||||
await fetchAreaData();
|
||||
|
||||
// 初始化时如果有区域编码,加载对应网格
|
||||
if (props.regionCode) {
|
||||
await fetchGridList(props.regionCode);
|
||||
}
|
||||
});
|
||||
|
||||
// 样式计算
|
||||
const containerStyle = computed(() => ({
|
||||
|
@ -2,6 +2,7 @@
|
||||
<div class="file-uploader">
|
||||
<el-upload
|
||||
class="file-uploader__upload"
|
||||
:class="{ hide: fileList.length >= limit }"
|
||||
:http-request="customUploadRequest"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-remove="handleRemove"
|
||||
@ -107,4 +108,8 @@ function handlePreview(file) {
|
||||
.file-uploader__upload {
|
||||
margin-right: 16px;
|
||||
}
|
||||
/* .el-upload--picture-card 控制加号部分 */
|
||||
:deep(.hide .el-upload--picture-card) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -11,19 +11,12 @@
|
||||
@remove-tag="$emit('remove-tag', $event)"
|
||||
@scroll="$emit('scroll', $event)"
|
||||
>
|
||||
<!-- 1. 原生 prefix 插槽 -->
|
||||
<slot name="prefix" />
|
||||
<!-- 2. 如果要实现分组插槽,也照搬 el-option-group 的结构 -->
|
||||
<template v-for="(_, name) in $slots" #[name]="scopedData">
|
||||
<slot :name="name" v-bind="scopedData"> </slot>
|
||||
</template>
|
||||
<slot name="option-group">
|
||||
<!-- 默认选项渲染 -->
|
||||
<el-option v-for="item in options" :key="item[valueKey]" :label="item[labelKey]" :value="item[valueKey]" />
|
||||
</slot>
|
||||
<!-- 3. 其他自定义插槽,不指定 name 的默认为 default slot -->
|
||||
<slot />
|
||||
<!-- 4. 下面这几个插槽是 el-select 也常见的: -->
|
||||
<slot name="empty" />
|
||||
<slot name="no-match" />
|
||||
<slot name="footer" />
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
|
331
sub-government-affairs-service/src/components/tableComponent.vue
Normal file
331
sub-government-affairs-service/src/components/tableComponent.vue
Normal file
@ -0,0 +1,331 @@
|
||||
<template>
|
||||
<div class="custom-table-container">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
style="flex: 1; display: flex; flex-direction: column; text-align: center"
|
||||
:max-height="tableMaxHeight"
|
||||
:data="tableData"
|
||||
:stripe="showStripe"
|
||||
:fit="true"
|
||||
v-bind="$attrs"
|
||||
:header-cell-class-name="headerCellClassName"
|
||||
:cell-class-name="cellClassName"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<!-- 树形展开 -->
|
||||
<el-table-column v-if="tree" type="expand" :header-class-name="headerCellClassName">
|
||||
<template #default="scope">
|
||||
<slot name="tree" :row="scope.row"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 首列多选框 -->
|
||||
<el-table-column v-if="showSelection" type="selection" width="30" align="center" fixed :header-class-name="headerCellClassName" />
|
||||
<el-table-column v-if="showSort" label="序号" width="70" fixed align="center" :header-class-name="headerCellClassName">
|
||||
<template #default="{ $index }">
|
||||
{{ (currentPage - 1) * pageSize + $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<template v-for="column in columns" :key="column.prop">
|
||||
<el-table-column
|
||||
:prop="column.prop"
|
||||
:label="column.label"
|
||||
:width="column.width"
|
||||
:align="column.align || 'center'"
|
||||
:fixed="column.fixed ?? false"
|
||||
:sortable="column.sortable"
|
||||
:header-class-name="column.headerClassName"
|
||||
>
|
||||
<!-- 支持插槽 -->
|
||||
<template v-if="column.slotName" #default="scope">
|
||||
<slot :name="column.slotName" :row="scope.row"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<div v-if="showPagination" class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="computedCurrentPage"
|
||||
v-model:page-size="computedPageSize"
|
||||
:page-sizes="pageSizes"
|
||||
:small="small"
|
||||
:disabled="disabled"
|
||||
:background="background"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="pageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 表格数据
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 列配置
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tree: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 当前页码(由外部传入)
|
||||
currentPage: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
// 每页数量(由外部传入)
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
// 总条数
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
// 是否显示分页
|
||||
showPagination: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否显示边框:border="showBorder"添加到组件会显示横竖边框,不添加只显示横边框
|
||||
showBorder: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否显示斑马纹
|
||||
showStripe: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否显示首列多选框
|
||||
showSelection: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否展示序号
|
||||
showSort: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 每页显示条数选项
|
||||
pageSizes: {
|
||||
type: Array,
|
||||
default: () => [10, 20, 30, 50],
|
||||
},
|
||||
// 是否使用小型分页样式
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否禁用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 是否为分页按钮添加背景色
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 自定义表头类名函数
|
||||
headerCellClassName: {
|
||||
type: Function,
|
||||
default: () => 'custom-header',
|
||||
},
|
||||
// 自定义单元格类名函数
|
||||
cellClassName: {
|
||||
type: Function,
|
||||
default: () => 'custom-cell',
|
||||
},
|
||||
rowkey: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:currentPage', 'update:pageSize', 'page-change', 'selection-change']);
|
||||
|
||||
// 每页数量(双向绑定)
|
||||
const computedPageSize = computed({
|
||||
get: () => props.pageSize,
|
||||
set: (val) => emit('update:pageSize', val),
|
||||
});
|
||||
// 当前页码(双向绑定)
|
||||
const computedCurrentPage = computed({
|
||||
get: () => props.currentPage,
|
||||
set: (val) => emit('update:currentPage', val),
|
||||
});
|
||||
|
||||
// 分页大小改变
|
||||
const pageSizeChange = (val) => {
|
||||
// console.log(`每页 ${val} 条`);
|
||||
// console.log(props.currentPage);
|
||||
emit('update:pageSize', val);
|
||||
emit('page-change', {
|
||||
page: props.currentPage,
|
||||
pageSize: val,
|
||||
});
|
||||
};
|
||||
|
||||
// 当前页改变
|
||||
const handleCurrentChange = (val) => {
|
||||
// console.log(`当前页改变 ${val} 页`);
|
||||
emit('page-change', {
|
||||
page: val,
|
||||
pageSize: props.pageSize,
|
||||
});
|
||||
};
|
||||
|
||||
// 多选框变化
|
||||
const handleSelectionChange = (selection) => {
|
||||
const selectedIds = selection.map((row) => (props.rowkey == '' ? row.id : row[props.rowkey]));
|
||||
emit('selection-change', selection, selectedIds);
|
||||
};
|
||||
|
||||
const tableRef = ref(null);
|
||||
const tableMaxHeight = ref(null); // 使用max-height而不是height
|
||||
|
||||
// 自动计算最大高度(预留分页器空间)
|
||||
const calculateMaxHeight = () => {
|
||||
const paginationHeight = 60; // 分页器固定高度
|
||||
const container = tableRef.value?.$el?.parentElement;
|
||||
if (container) {
|
||||
const containerHeight = container.clientHeight;
|
||||
tableMaxHeight.value = containerHeight - paginationHeight;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
calculateMaxHeight();
|
||||
window.addEventListener('resize', calculateMaxHeight);
|
||||
|
||||
// 添加MutationObserver监听父容器尺寸变化
|
||||
const observer = new MutationObserver(calculateMaxHeight);
|
||||
if (tableRef.value?.$el?.parentElement) {
|
||||
observer.observe(tableRef.value.$el.parentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['style', 'class'],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', calculateMaxHeight);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-table-container {
|
||||
// position: relative;
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%; /* 关键:继承父容器高度 */
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
|
||||
/* 表格弹性布局 */
|
||||
:deep(.el-table) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
/* 表头固定 */
|
||||
.el-table__header-wrapper {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 表体可滚动 */
|
||||
.el-table__body-wrapper {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.demo-form-inline {
|
||||
text-align: left;
|
||||
padding-left: 20px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 20px;
|
||||
padding: 0 30px 0 20px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
color: #999;
|
||||
font-weight: 400;
|
||||
}
|
||||
.custom-pagination-text {
|
||||
flex: 1;
|
||||
text-align: left;
|
||||
line-height: 32px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.custom-pagination-size {
|
||||
text-align: right;
|
||||
line-height: 32px;
|
||||
margin-left: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 去除表格边框 */
|
||||
// :deep(.el-table) {
|
||||
// --el-table-border-color: transparent;
|
||||
// }
|
||||
|
||||
/* 自定义鼠标悬停颜色 */
|
||||
// :deep(.el-table__body tr:hover > td) {
|
||||
// background-color: rgba(237 255 248) !important;
|
||||
// }
|
||||
|
||||
/* 自定义表头样式 */
|
||||
:deep(.custom-header) {
|
||||
color: #333;
|
||||
background-color: #fafafa !important;
|
||||
}
|
||||
/* 自定义单元格样式 */
|
||||
:deep(.custom-cell) {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
:deep(.el-pagination) {
|
||||
/* 整体分页样式 */
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
|
||||
/* 每页条数选择器 */
|
||||
.el-pagination__sizes {
|
||||
.el-input__inner {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
/* 跳页输入框 */
|
||||
.el-pagination__jump {
|
||||
font-weight: 400;
|
||||
// position: absolute;
|
||||
// right: 16px;
|
||||
// bottom: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
import { ref } from 'vue';
|
||||
import { fetchLandList, deleteLand, createLand, updateLand } from '@/apis/landResourceManagement/landManagement';
|
||||
import { createLand, deleteLand, editLand, fetchLandList, getLandById } from '@/apis/landResourceManagement/landManagement';
|
||||
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
@ -36,7 +36,7 @@ export function useLandCrud(type) {
|
||||
await createLand({ ...data, type });
|
||||
ElMessage.success('新增成功');
|
||||
} else {
|
||||
await updateLand(data);
|
||||
await editLand(data);
|
||||
ElMessage.success('更新成功');
|
||||
}
|
||||
formVisible.value = false;
|
||||
|
55
sub-government-affairs-service/src/config/map.js
Normal file
55
sub-government-affairs-service/src/config/map.js
Normal file
@ -0,0 +1,55 @@
|
||||
export const map_config = {
|
||||
tianditu: {
|
||||
version: '4.0',
|
||||
token: '5e3204b9312c1d2618049d90a4ae917c',
|
||||
center: [100.088, 23.883],
|
||||
zoom: 13,
|
||||
},
|
||||
|
||||
baseMaps: [
|
||||
{
|
||||
label: 'OSM街道图',
|
||||
Url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
},
|
||||
{
|
||||
label: 'ArcGIS影像图',
|
||||
Url: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
|
||||
},
|
||||
{
|
||||
label: 'ArcGIS街道图',
|
||||
Url: 'http://cache1.arcgisonline.cn/arcgis/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}',
|
||||
},
|
||||
{
|
||||
label: '天地图街道图',
|
||||
Url: 'http://t{s}.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=7786923a385369346d56b966bb6ad62f',
|
||||
},
|
||||
{
|
||||
label: '天地图影像图',
|
||||
Url: 'http://t{s}.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=7786923a385369346d56b966bb6ad62f',
|
||||
},
|
||||
{
|
||||
label: '谷歌街道图',
|
||||
Url: 'http://www.google.cn/maps/vt?lyrs=m@189&gl=cn&x={x}&y={y}&z={z}',
|
||||
},
|
||||
{
|
||||
label: '谷歌影像图',
|
||||
Url: 'http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}',
|
||||
},
|
||||
{
|
||||
label: '高德街道图',
|
||||
Url: 'http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
|
||||
},
|
||||
{
|
||||
label: '高德影像图',
|
||||
Url: 'http://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
|
||||
},
|
||||
{
|
||||
label: '百度街道图',
|
||||
Url: 'http://online{s}.map.bdimg.com/onlinelabel/?qt=tile&x={x}&y={y}&z={z}&styles={styles}&scaler=1&p=1',
|
||||
},
|
||||
{
|
||||
label: '百度影像图',
|
||||
Url: 'http://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46',
|
||||
},
|
||||
],
|
||||
};
|
@ -8,14 +8,20 @@ import 'element-plus/dist/index.css';
|
||||
import Avue from '@smallwei/avue';
|
||||
import '@smallwei/avue/lib/index.css';
|
||||
import './utils/permission';
|
||||
import './styles/custom.scss';
|
||||
import { registerDirective } from './directives';
|
||||
import { registerGlobalComponents } from './plugins/globalComponents';
|
||||
import { registerElIcons } from './plugins/icon';
|
||||
import { registerMicroApps } from './plugins/micro';
|
||||
import { registerSplitpanes } from './plugins/splitpanes';
|
||||
import VueTianditu from 'vue-tianditu';
|
||||
import { map_config } from './config/map';
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(pinia).use(router).use(ElementPlus).use(Avue);
|
||||
app.use(pinia).use(router).use(ElementPlus).use(Avue).use(VueTianditu, {
|
||||
v: map_config.tianditu.version,
|
||||
tk: map_config.tianditu.token,
|
||||
});
|
||||
registerGlobalComponents(app);
|
||||
registerElIcons(app);
|
||||
registerSplitpanes(app);
|
||||
|
@ -9,6 +9,18 @@ const inputSuppliesRoutes = [
|
||||
redirect: '/sub-government-affairs-service/material/pesticide',
|
||||
meta: { title: '农产品种植管理', icon: 'FullScreen' },
|
||||
children: [
|
||||
{
|
||||
path: '/sub-government-affairs-service/statistics',
|
||||
name: 'Statistics',
|
||||
component: () => import('@/views/planting-management/statistics/index.vue'),
|
||||
meta: { title: '使用监管概况统计', icon: 'PieChart' },
|
||||
},
|
||||
{
|
||||
path: '/sub-government-affairs-service/variety-record',
|
||||
name: 'PlantVarietyRecord',
|
||||
component: () => import('@/views/planting-management/variety-record/index.vue'),
|
||||
meta: { title: '农产品种植品种备案', icon: 'Calendar' },
|
||||
},
|
||||
{
|
||||
path: '/sub-government-affairs-service/material/annualPlans',
|
||||
name: 'annualPlans',
|
||||
|
348
sub-government-affairs-service/src/styles/custom.scss
Normal file
348
sub-government-affairs-service/src/styles/custom.scss
Normal file
@ -0,0 +1,348 @@
|
||||
.app-container {
|
||||
.container-custom {
|
||||
width: 100%;
|
||||
overflow: hidden; /* 防止全局滚动条 */
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
|
||||
.custom-h2 {
|
||||
margin: 14px 0 0 20px;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
overflow: hidden;
|
||||
padding: 16px 8px 0 16px;
|
||||
background: #fff;
|
||||
.order-tab {
|
||||
width: 100%;
|
||||
.el-tabs__nav-wrap::after {
|
||||
background: transparent !important;
|
||||
}
|
||||
.el-tabs__active-bar {
|
||||
height: 3px !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.el-descriptions__label,
|
||||
.el-descriptions__content {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
.cell-item {
|
||||
display: inline-flex;
|
||||
}
|
||||
.el-descriptions__label {
|
||||
color: #999;
|
||||
}
|
||||
.el-descriptions__content {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-bar {
|
||||
display: flex;
|
||||
flex-shrink: 0; /* 禁止收缩 */
|
||||
|
||||
.search-bar-left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.search-bar-right {
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.demo-form-inline {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.el-form--inline .el-form-item {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.demo-form-inline .el-input {
|
||||
--el-input-width: 160px;
|
||||
}
|
||||
|
||||
.demo-form-inline .el-select {
|
||||
--el-select-width: 160px;
|
||||
}
|
||||
|
||||
.demo-form-inline .el-date-picker {
|
||||
--el-select-width: 160px;
|
||||
}
|
||||
.el-form .el-form-item__label {
|
||||
font-weight: 400;
|
||||
}
|
||||
.custom-form-inline .el-input {
|
||||
width: 260px;
|
||||
}
|
||||
}
|
||||
.table-toolbar {
|
||||
text-align: left;
|
||||
padding-left: 20px;
|
||||
padding-top: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.table-cont {
|
||||
padding: 10px 20px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
.el-table__empty-text {
|
||||
width: 200px;
|
||||
}
|
||||
.el-button-custom{
|
||||
font-size: 14px !important;
|
||||
color: #25bf82;
|
||||
padding: 0;
|
||||
}
|
||||
.el-button-delete{
|
||||
font-size: 14px !important;
|
||||
color: #ff4d4f;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 自定义弹窗样式 */
|
||||
.traceability-dialog {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
|
||||
/* 主要内容区域 */
|
||||
.dialog-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 0 0 20px 0;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 产品信息 */
|
||||
.product-info {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 二维码图片 */
|
||||
.qrcode-image {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* 下载区域 */
|
||||
.download-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 0 10px 0;
|
||||
color: #25bf82;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.download-icon {
|
||||
margin-left: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 遗传编码区域 */
|
||||
.code-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 10px 0;
|
||||
background: rgba(37, 191, 130, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.genetic-code {
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
color: #25bf82;
|
||||
display: inline-block;
|
||||
max-width: 250px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.copy-icon {
|
||||
margin-left: 10px;
|
||||
color: #409eff;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 关闭按钮 */
|
||||
.close-button {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: -60px;
|
||||
color: white;
|
||||
font-size: 30px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
// 表格中文本的颜色
|
||||
.color-blue {
|
||||
color: #3685fe;
|
||||
}
|
||||
.color-black {
|
||||
color: #000000;
|
||||
}
|
||||
.color-gray {
|
||||
color: #5a5a5a;
|
||||
}
|
||||
.color-orange {
|
||||
color: #ffb345;
|
||||
}
|
||||
.color-green {
|
||||
color: #25bf82;
|
||||
}
|
||||
.color-red {
|
||||
color: #ff4348;
|
||||
}
|
||||
}
|
||||
.el-button {
|
||||
font-size: 12px !important;
|
||||
font-weight: 400;
|
||||
}
|
||||
// 页面添加的自定义容器,上下撑满
|
||||
.customer-control {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
min-width: 1000px;
|
||||
}
|
||||
// 表格组件中的各插槽元素自定义样式
|
||||
.custom-tooltip-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding: 3px 0;
|
||||
|
||||
}
|
||||
.el-icon-custom {
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
// color: #fff;
|
||||
}
|
||||
.table-cell-img-box {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
overflow: hidden; /* 隐藏超出部分 */
|
||||
display: flex; /* 使用 Flex 布局居中 */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.table-cell-img {
|
||||
min-width: 100%; /* 至少撑满宽度 */
|
||||
min-height: 100%; /* 至少撑满高度 */
|
||||
object-fit: cover; /* 保持比例并覆盖容器 */
|
||||
}
|
||||
}
|
||||
|
||||
// 新增商品页面-开始
|
||||
.customer-box {
|
||||
height: 100%;
|
||||
border-radius: 16px;
|
||||
padding: 20px 16px;
|
||||
overflow-y: auto;
|
||||
background-color: #fff;
|
||||
.my-el-select {
|
||||
width: 200px;
|
||||
}
|
||||
.el-input-number .el-input__inner {
|
||||
text-align: left;
|
||||
}
|
||||
// 商品属性
|
||||
.attr-item {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
.el-icon {
|
||||
vertical-align: middle;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
.attr-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: nowrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.attr-input {
|
||||
width: 120px;
|
||||
}
|
||||
.attr-clomn {
|
||||
width: 160px;
|
||||
}
|
||||
.attr-clomn200 {
|
||||
width: 160px;
|
||||
}
|
||||
.attr-clomn220 {
|
||||
width: 220px;
|
||||
}
|
||||
.attr-box {
|
||||
padding: 16px 16px 6px 16px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
}
|
||||
// 新增商品页面-结束
|
||||
|
||||
// 弹性布局-左对齐-上对齐
|
||||
.flex-left-top {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
// 溢出隐藏
|
||||
.text-ellipsis {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// 弹窗表单样式-子元素一行2个列
|
||||
.dialog-form-container {
|
||||
.dialog-form-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.dialog-form-item{
|
||||
margin-right: 20px;
|
||||
.el-input,
|
||||
.el-select {
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
.dialog-form-many {
|
||||
position: relative;
|
||||
.dialog-form-many-delete {
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,624 @@
|
||||
<template>
|
||||
<section class="custom-page">
|
||||
<h2>农药使用监管</h2>
|
||||
<!-- <TypeMenu v-if="materialTypes[1].length > 1" v-model:type="_type" :types="materialTypes['1']" /> -->
|
||||
<br />
|
||||
<avue-crud
|
||||
ref="crud"
|
||||
v-model:page="pageData"
|
||||
v-model:search="searchCondition"
|
||||
:table-loading="_loading"
|
||||
:data="data"
|
||||
:option="option"
|
||||
:before-close="handleCloseDialog"
|
||||
@search-change="
|
||||
(form, done) => {
|
||||
getData(1);
|
||||
done();
|
||||
}
|
||||
"
|
||||
@search-reset="getData(1)"
|
||||
@refresh-change="getData"
|
||||
@current-change="getData"
|
||||
@size-change="getData(1)"
|
||||
@row-save="handleRowSave"
|
||||
@row-update="handleRowUpdate"
|
||||
>
|
||||
<template #menu="scope">
|
||||
<custom-table-operate :actions="actions" :data="scope" />
|
||||
</template>
|
||||
<template #photoUrl-form="{ type }">
|
||||
<Attrs v-model:attrs="attrs" :type="type == 'add' ? 'add' : 'view'" :limit="2" />
|
||||
</template>
|
||||
<template #checkInfo-form="{ row }">
|
||||
<section style="text-align: center; line-height: 58px">
|
||||
<el-button @click="handleCheckInfo('open')">查看报告</el-button>
|
||||
</section>
|
||||
</template>
|
||||
<template #detectionReport-form="{ type }">
|
||||
<Attrs v-model:attrs="reportAttrs" :type="type" :up-btn="reportAttrs.length < 1" :file-num="reportAttrs.length > 0 ? 1 : 3" :limit="2" />
|
||||
</template>
|
||||
<template #productSpecification-form="{ value, type }">
|
||||
<NumberSelect v-if="type == 'add'" v-model:value="productSpecification" :options="goodsUnitOptions" />
|
||||
<span v-if="type == 'view'">{{ value }}</span>
|
||||
</template>
|
||||
<template #dosage-form="{ value, type }">
|
||||
<NumberSelect v-if="type == 'add'" v-model:value="useDosage" :options="useDosageUnit" />
|
||||
<span v-if="type == 'view'">{{ value }}</span>
|
||||
</template>
|
||||
<template #checkBtn-form>
|
||||
<section style="text-align: center; line-height: 58px">
|
||||
<el-button @click="handleCheckInfo('close')">关闭</el-button>
|
||||
</section>
|
||||
</template>
|
||||
</avue-crud>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import TypeMenu from '../../common/TypeMenu.vue';
|
||||
import { CRUD_OPTIONS, customRules } 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';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import assistFn from '@/views/inputSuppliesManage/hooks/useAssistFn';
|
||||
const { deleteFn } = new assistFn();
|
||||
|
||||
const { defaultGet, loadFinish, materialTypes, materialTwoLevel, goodsUnitOptions, useDosageUnit, handleNumUnit, handleShowName, targetName } =
|
||||
useBasicInfo({
|
||||
moduleType: '1',
|
||||
});
|
||||
const { getPesticideList, addPesticide, pesticideReportSave, delPesticide } = inputSuppliesApi;
|
||||
|
||||
/* --------------- data --------------- */
|
||||
// #region
|
||||
const _type = ref('0');
|
||||
watch(
|
||||
() => _type.value,
|
||||
() => getData(1),
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
const searchCondition = ref({
|
||||
name: '',
|
||||
phone: '',
|
||||
});
|
||||
const crud = ref();
|
||||
const _loading = ref(true);
|
||||
const data = ref([]);
|
||||
const pageData = ref({
|
||||
total: 0,
|
||||
currentPage: 1,
|
||||
size: 10,
|
||||
});
|
||||
|
||||
const dicDatas = ref({
|
||||
_targetPests: {
|
||||
one: '1',
|
||||
two: '1',
|
||||
dic: [],
|
||||
},
|
||||
_mainComponent: {
|
||||
one: '1',
|
||||
two: '2',
|
||||
dic: [],
|
||||
},
|
||||
_produceDosage: {
|
||||
one: '1',
|
||||
two: '3',
|
||||
dic: [],
|
||||
},
|
||||
});
|
||||
const option = ref({
|
||||
...CRUD_OPTIONS,
|
||||
selection: false,
|
||||
labelWidth: 124,
|
||||
editBtn: false,
|
||||
delBtn: false,
|
||||
dialogWidth: '60%',
|
||||
updateBtnText: '上传报告',
|
||||
column: [
|
||||
// 查询条件
|
||||
{
|
||||
hide: true,
|
||||
label: '姓名',
|
||||
prop: 'name',
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
searchPlaceholder: '请输入姓名',
|
||||
viewDisplay: false,
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '手机号',
|
||||
prop: 'phone',
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
searchPlaceholder: '请输入手机号',
|
||||
viewDisplay: false,
|
||||
},
|
||||
// 弹窗字段
|
||||
{
|
||||
prop: 'name',
|
||||
label: '姓名',
|
||||
width: '120',
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '请输入姓名' }),
|
||||
},
|
||||
{
|
||||
prop: 'phone',
|
||||
label: '联系方式',
|
||||
width: '220',
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '请输入联系方式' }),
|
||||
},
|
||||
{
|
||||
prop: 'landName',
|
||||
width: '200',
|
||||
label: '用药地块',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: 'photoUrl',
|
||||
label: '检测报告',
|
||||
span: 24,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: 'pesticideRegistCode',
|
||||
label: '农药登记证号',
|
||||
width: '120',
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '请输登记证号' }),
|
||||
},
|
||||
{
|
||||
prop: 'manufacturer',
|
||||
label: '生产厂家',
|
||||
width: '220',
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '请输入生产厂家' }),
|
||||
},
|
||||
{
|
||||
prop: 'productSpecification',
|
||||
width: '100',
|
||||
label: '产品规格',
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
prop: 'toxicityLevel',
|
||||
width: '140',
|
||||
label: '毒性',
|
||||
editDisplay: false,
|
||||
value: '无毒',
|
||||
},
|
||||
{
|
||||
prop: 'dosage',
|
||||
width: '140',
|
||||
label: '建议用量',
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
prop: 'expiryDate',
|
||||
label: '保质期',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
prop: 'targetPests',
|
||||
width: '200',
|
||||
label: '防治对象',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
prop: 'mainComponent',
|
||||
width: '200',
|
||||
label: '化学成分',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
prop: 'produceDosage',
|
||||
width: '200',
|
||||
label: '加工剂型',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: '_targetPests',
|
||||
label: '防治对象',
|
||||
type: 'cascader',
|
||||
multiple: true,
|
||||
dicData: [],
|
||||
value: [],
|
||||
span: 24,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '请选择防治对象' }),
|
||||
expandTrigger: 'click',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: '_mainComponent',
|
||||
label: '化学成分',
|
||||
type: 'cascader',
|
||||
multiple: true,
|
||||
dicData: [],
|
||||
value: [],
|
||||
span: 24,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '请选择主要成分' }),
|
||||
expandTrigger: 'click',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: '_produceDosage',
|
||||
label: '加工剂型',
|
||||
type: 'cascader',
|
||||
multiple: true,
|
||||
dicData: [],
|
||||
value: [],
|
||||
span: 24,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: customRules({ msg: '加工剂型' }),
|
||||
expandTrigger: 'click',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: 'usageMethod',
|
||||
label: '使用方法',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
prop: 'precautions',
|
||||
label: '注意事项',
|
||||
type: 'textarea',
|
||||
span: 24,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
labelWidth: 0,
|
||||
border: false,
|
||||
prop: 'checkInfo',
|
||||
span: 24,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
],
|
||||
group: [
|
||||
{
|
||||
label: '农药基本信息',
|
||||
prop: 'basic_info',
|
||||
addDisplay: false,
|
||||
viewDisplay: false,
|
||||
column: [
|
||||
{
|
||||
prop: 'pesticideName',
|
||||
label: '农药名称',
|
||||
editDisabled: true,
|
||||
span: 24,
|
||||
},
|
||||
{
|
||||
prop: 'manufacturer',
|
||||
label: '生产商',
|
||||
editDisabled: true,
|
||||
span: 24,
|
||||
},
|
||||
{
|
||||
prop: 'distributor',
|
||||
label: '经销商',
|
||||
editDisabled: true,
|
||||
span: 24,
|
||||
},
|
||||
{
|
||||
prop: 'photoUrl',
|
||||
label: '农药图片',
|
||||
editDisabled: true,
|
||||
span: 24,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '农药检测信息',
|
||||
prop: 'check_info',
|
||||
addDisplay: false,
|
||||
viewDisplay: false,
|
||||
column: [
|
||||
{
|
||||
prop: 'detectionTime',
|
||||
label: '检测时间',
|
||||
type: 'date',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
rules: customRules({ msg: '请选择检测时间' }),
|
||||
},
|
||||
{
|
||||
prop: 'detectionResult',
|
||||
label: '检测结果',
|
||||
type: 'select',
|
||||
clearable: false,
|
||||
rules: customRules({ msg: '请选择检测结果' }),
|
||||
dicData: [
|
||||
{ value: '0', label: '合格' },
|
||||
{ value: '1', label: '不合格' },
|
||||
],
|
||||
value: '0',
|
||||
},
|
||||
{
|
||||
prop: 'detectionUnit',
|
||||
label: '检测单位',
|
||||
rules: customRules({ msg: '请输入检测单位' }),
|
||||
},
|
||||
{
|
||||
prop: 'detectionConclusion',
|
||||
label: '检测结论',
|
||||
rules: customRules({ msg: '请输入检测结论' }),
|
||||
},
|
||||
{
|
||||
prop: 'detectionReport',
|
||||
label: '质检报告',
|
||||
span: 24,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
trigger: ['blur', 'change'],
|
||||
validator: (rule, value, callback) => {
|
||||
if (!reportAttrs.value.length) {
|
||||
callback(new Error('请上传检测报告'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
labelWidth: 0,
|
||||
prop: 'checkBtn',
|
||||
span: 24,
|
||||
editDisplay: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
watch(
|
||||
() => loadFinish.value,
|
||||
() => {
|
||||
if (loadFinish.value) {
|
||||
for (let key in dicDatas.value) {
|
||||
option.value.column.forEach((item) => {
|
||||
if (item.prop === key) {
|
||||
let dic = materialTwoLevel?.[dicDatas.value[key].one]?.[dicDatas.value[key].two] ?? [];
|
||||
dicDatas.value[key].dic = dic;
|
||||
item.dicData = dic;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
const attrs = ref([]);
|
||||
const reportAttrs = ref([]);
|
||||
const productSpecification = ref({
|
||||
num: 1,
|
||||
type: '1',
|
||||
});
|
||||
const useDosage = ref({
|
||||
num: 1,
|
||||
type: '1',
|
||||
});
|
||||
const actions = ref([
|
||||
{
|
||||
name: '编辑',
|
||||
icon: 'view',
|
||||
event: ({ row }) => handleEdit(row),
|
||||
},
|
||||
{
|
||||
name: '详情',
|
||||
icon: 'view',
|
||||
event: ({ row }) => handleInfo(row),
|
||||
},
|
||||
{
|
||||
type: 'danger',
|
||||
name: '删除',
|
||||
icon: 'delete',
|
||||
event: ({ row }) => deleteFn(row.id, delPesticide, getData),
|
||||
},
|
||||
]);
|
||||
// #endregion
|
||||
|
||||
/* --------------- methods --------------- */
|
||||
// #region
|
||||
|
||||
defaultGet(getData);
|
||||
async function getData(reset) {
|
||||
_loading.value = true;
|
||||
reset == 1 && (pageData.value.currentPage = 1);
|
||||
let params = {
|
||||
current: pageData.value.currentPage,
|
||||
size: pageData.value.size,
|
||||
name: searchCondition.value.name,
|
||||
phone: searchCondition.value.phone,
|
||||
};
|
||||
_type.value != '0' && (params.classifyId = _type.value);
|
||||
let res = await getPesticideList(params);
|
||||
console.log('res --- ', res);
|
||||
_loading.value = false;
|
||||
if (res && res.code === 200) {
|
||||
data.value = res.data.records;
|
||||
// data.value.forEach((v) => {
|
||||
// v.productSpecification = handleNumUnit({ num1: v.productSpecification, unit1: v.productUnit, type: 1 });
|
||||
// v.dosage = handleNumUnit({ unit1: v.productUnit, num2: v.suggestDosage, unit2: v.suggestUnit, type: -1 });
|
||||
// v.targetPests = handleShowName(v.targetPests);
|
||||
// v.mainComponent = handleShowName(v.mainComponent);
|
||||
// v.produceDosage = handleShowName(v.produceDosage);
|
||||
// });
|
||||
pageData.value.total = res.data.total;
|
||||
}
|
||||
}
|
||||
function handleCloseDialog(done) {
|
||||
delete option.value.column[1].span;
|
||||
resetOtherInfo();
|
||||
handleCheckInfoChange();
|
||||
done();
|
||||
}
|
||||
|
||||
async function handleRowSave(form, done, loading) {
|
||||
let data = {
|
||||
pesticideName: form.pesticideName,
|
||||
productStandCode: form.productStandCode,
|
||||
pesticideRegistCode: form.pesticideRegistCode,
|
||||
manufacturer: form.manufacturer,
|
||||
distributor: form.distributor,
|
||||
toxicityLevel: form.toxicityLevel,
|
||||
usageMethod: form.usageMethod,
|
||||
precautions: form.precautions,
|
||||
expiryDate: form.expiryDate,
|
||||
productSpecification: productSpecification.value.num,
|
||||
productUnit: productSpecification.value.type,
|
||||
suggestDosage: useDosage.value.num,
|
||||
suggestUnit: useDosage.value.type,
|
||||
};
|
||||
if (attrs.value.length) {
|
||||
data.photoUrl = attrs.value.map((v) => v.url).join();
|
||||
}
|
||||
if (form._targetPests.length) {
|
||||
let names = [];
|
||||
form._targetPests.forEach((item) => {
|
||||
names.push(targetName(dicDatas.value._targetPests.dic, item, ''));
|
||||
});
|
||||
data.targetPests = JSON.stringify(form._targetPests) + '|' + JSON.stringify(names);
|
||||
}
|
||||
if (form._mainComponent.length) {
|
||||
let names = [];
|
||||
form._mainComponent.forEach((item) => {
|
||||
names.push(targetName(dicDatas.value._mainComponent.dic, item, ''));
|
||||
});
|
||||
data.mainComponent = JSON.stringify(form._mainComponent) + '|' + JSON.stringify(names);
|
||||
}
|
||||
if (form._produceDosage.length) {
|
||||
let names = [];
|
||||
form._produceDosage.forEach((item) => {
|
||||
names.push(targetName(dicDatas.value._produceDosage.dic, item, ''));
|
||||
});
|
||||
data.produceDosage = JSON.stringify(form._produceDosage) + '|' + JSON.stringify(names);
|
||||
}
|
||||
let res = await addPesticide(data);
|
||||
loading();
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('保存成功');
|
||||
getData();
|
||||
resetOtherInfo();
|
||||
done();
|
||||
}
|
||||
}
|
||||
function resetOtherInfo() {
|
||||
let obj = { num: 1, type: '1' };
|
||||
attrs.value = [];
|
||||
reportAttrs.value = [];
|
||||
productSpecification.value = obj;
|
||||
useDosage.value = obj;
|
||||
}
|
||||
|
||||
function handleEdit(row) {
|
||||
handleAttrs(row);
|
||||
option.value.group[1].column[0].value = row.detectionTime;
|
||||
option.value.group[1].column[1].value = row.detectionResult;
|
||||
option.value.group[1].column[2].value = row.detectionUnit;
|
||||
option.value.group[1].column[3].value = row.detectionConclusion;
|
||||
handleCheckInfoChange('open');
|
||||
crud.value.rowEdit(row);
|
||||
}
|
||||
function handleInfo(row) {
|
||||
handleAttrs(row);
|
||||
option.value.column[1].span = 24;
|
||||
crud.value.rowView(row);
|
||||
}
|
||||
/* 处理展示附件 */
|
||||
function handleAttrs(row = {}) {
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
if (row.photoUrl) {
|
||||
attrs.value = row.photoUrl.split(',').map((v, i) => {
|
||||
return {
|
||||
url: v,
|
||||
uid: `photo_${i}_${Date.now()}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (row.detectionReport) {
|
||||
reportAttrs.value = row.detectionReport.split(',').map((v, i) => {
|
||||
return {
|
||||
url: v,
|
||||
uid: `report_${i}_${Date.now()}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
function handleCheckInfo(type) {
|
||||
handleCheckInfoChange(type == 'open');
|
||||
}
|
||||
/* bol && 查看检测报告关闭其他信息 !bol && 关闭检测报告打开其他信息 */
|
||||
function handleCheckInfoChange(bol = false) {
|
||||
option.value.group.forEach((v) => {
|
||||
v.viewDisplay = bol;
|
||||
});
|
||||
if (bol) {
|
||||
option.value.column.forEach((v) => {
|
||||
v.viewDisplay = false;
|
||||
});
|
||||
} else {
|
||||
option.value.column.forEach((v) => {
|
||||
if (!v.hide || v.prop == 'photoUrl') {
|
||||
v.viewDisplay = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
async function handleRowUpdate(form, index, done, loading) {
|
||||
console.log('update from -- ', form);
|
||||
let data = {
|
||||
id: form.id,
|
||||
detectionTime: form.detectionTime,
|
||||
detectionResult: form.detectionResult,
|
||||
detectionUnit: form.detectionUnit,
|
||||
detectionConclusion: form.detectionConclusion,
|
||||
detectionReport: reportAttrs.value.map((v) => v.url).join(),
|
||||
};
|
||||
let res = await pesticideReportSave(data);
|
||||
loading();
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('检测报告保存成功');
|
||||
getData();
|
||||
done();
|
||||
}
|
||||
}
|
||||
// #endregion
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
font-family: '黑体';
|
||||
}
|
||||
</style>
|
@ -1,263 +1,413 @@
|
||||
<template>
|
||||
<section class="custom-page">
|
||||
<h2>种子基本信息</h2>
|
||||
<TypeMenu v-if="materialTypes['4'].length > 1" v-model:type="_type" :types="materialTypes['4']" />
|
||||
<br />
|
||||
<avue-crud
|
||||
ref="crudRef"
|
||||
v-model:page="pageData"
|
||||
v-model:search="searchCondition"
|
||||
:table-loading="_loading"
|
||||
:before-close="handleCloseDialog"
|
||||
:data="data"
|
||||
:option="option"
|
||||
@search-change="
|
||||
(form, done) => {
|
||||
getData(1);
|
||||
done();
|
||||
}
|
||||
"
|
||||
@search-reset="getData(1)"
|
||||
@refresh-change="getData"
|
||||
@current-change="getData"
|
||||
@size-change="getData(1)"
|
||||
@row-save="handleRowSave"
|
||||
>
|
||||
<template #menu="{ row }">
|
||||
<el-button type="primary" @click="handleInfo(row)">详情</el-button>
|
||||
<el-button @click="deleteFn(row.id, delSeed, getData)">删除</el-button>
|
||||
<div class="app-container">
|
||||
<div class="container-custom">
|
||||
<h2 class="custom-h2">种子种苗管理</h2>
|
||||
<div ref="searchBarRef" class="search-box">
|
||||
<div class="search-bar">
|
||||
<div class="search-bar-left">
|
||||
<el-form ref="searchForm" :inline="true" :model="formInline" class="demo-form-inline" :label-width="'auto'">
|
||||
<el-form-item label="关键字" prop="seedName">
|
||||
<el-input v-model="formInline.seedName" placeholder="请输入姓名" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="分类" prop="seedTypeId">
|
||||
<el-select v-model="formInline.seedTypeId" placeholder="请选择" clearable @change="seedTypeChange">
|
||||
<el-option v-for="item in seedTypeList" :key="item.id" :value="item.id" :label="item.dataName" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="">
|
||||
<el-button type="primary" icon="Search" @click="onSubmit">查询</el-button>
|
||||
<el-button icon="Refresh" @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-toolbar">
|
||||
<el-button type="primary" icon="plus" @click="addItem()">新增</el-button>
|
||||
</div>
|
||||
<div class="table-cont">
|
||||
<tableComponent
|
||||
:table-data="tableData"
|
||||
:columns="columns"
|
||||
:show-selection="false"
|
||||
:loading="tableLoading"
|
||||
:total="tableTotal"
|
||||
:current-page="formInline.current"
|
||||
:page-size="formInline.size"
|
||||
:show-sort="true"
|
||||
@page-change="handlePaginationChange"
|
||||
>
|
||||
<!-- 自定义-操作 -->
|
||||
<template #action="slotProps">
|
||||
<el-button type="primary" @click="seeDetails(slotProps.row)">查看</el-button>
|
||||
<el-button type="primary" @click="handleEdit(slotProps.row)">编辑</el-button>
|
||||
<el-button @click="handleDelete(slotProps.row)">删除</el-button>
|
||||
</template>
|
||||
</tableComponent>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog v-model="dialogFormVisible" :title="dialogTitle" width="800" :close-on-click-modal="false">
|
||||
<el-form
|
||||
ref="dialogRef"
|
||||
:model="dialogForm"
|
||||
:inline="true"
|
||||
:label-width="'120'"
|
||||
:rules="dialogFormRules"
|
||||
:disabled="formDisabled"
|
||||
class="dialog-form-container"
|
||||
>
|
||||
<el-form-item label="种子种苗名称" prop="seedName" class="dialog-form-item">
|
||||
<el-input v-model="dialogForm.seedName" clearable placeholder="请输入种子种苗名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="品种名称" prop="varietyName" class="dialog-form-item">
|
||||
<el-input v-model="dialogForm.varietyName" clearable placeholder="请输入品种名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="品牌" prop="brand" class="dialog-form-item">
|
||||
<el-input v-model="dialogForm.brand" clearable placeholder="请输入品牌" />
|
||||
</el-form-item>
|
||||
<el-form-item label="生产厂家" prop="manufacturer" class="dialog-form-item">
|
||||
<el-input v-model="dialogForm.manufacturer" clearable placeholder="请输入生产厂家" />
|
||||
</el-form-item>
|
||||
<el-form-item label="蔬菜种苗" prop="classifyId" class="dialog-form-item">
|
||||
<el-cascader
|
||||
v-model="dialogForm.classifyId"
|
||||
:options="seedTypeDialogList"
|
||||
:props="cascaderProps"
|
||||
placeholder="请选择"
|
||||
@change="handleCascaderChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="产品规格" prop="productUnit" class="dialog-form-item">
|
||||
<el-input v-model="dialogForm.productUnit" clearable placeholder="请输入产品规格" />
|
||||
</el-form-item>
|
||||
|
||||
<div style="display: flex">
|
||||
<div style="width: 50%; display: inline-block">
|
||||
<el-form-item label="种子种苗主图" prop="photoUrl" class="dialog-form-item" style="width: 100%">
|
||||
<FileUploader v-model="dialogForm.photoUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div style="width: 50%; display: inline-block">
|
||||
<el-form-item label="种子种苗详情图" prop="photoUrlDetail" class="dialog-form-item" style="width: 100%">
|
||||
<FileUploader v-model="dialogForm.photoUrlDetail" :limit="1" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button v-if="!formDisabled" type="primary" @click="onSaveCategory">保存</el-button>
|
||||
<el-button v-if="!formDisabled" @click="cancelDialog">取消</el-button>
|
||||
<el-button v-else @click="cancelDialog">关闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #photoUrl-form="{ type }"> <Attrs v-model:attrs="attrs" :type="type == 'add' ? 'add' : 'view'" :limit="2" /> </template>
|
||||
</avue-crud>
|
||||
</section>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, pushScopeId } from 'vue';
|
||||
import TypeMenu from '../../common/TypeMenu.vue';
|
||||
import { CRUD_OPTIONS, pageData, customRules } from '@/config';
|
||||
import { useBasicInfo } from '@/views/inputSuppliesManage/hooks/useBasicInfo';
|
||||
import Attrs from '@/views/inputSuppliesManage/common/Attrs.vue';
|
||||
import inputSuppliesapi from '@/apis/inputSuppliesApi';
|
||||
import { ref, reactive, computed, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||
import tableComponent from '@/components/tableComponent.vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import assistFn from '@/views/inputSuppliesManage/hooks/useAssistFn';
|
||||
const { deleteFn } = new assistFn();
|
||||
const { getSeedList, seedSave, delSeed } = inputSuppliesapi;
|
||||
const { loadFinish, materialTypes, targetName } = useBasicInfo({
|
||||
moduleType: '4',
|
||||
import inputSuppliesApi from '@/apis/inputSuppliesApi';
|
||||
const { getSeedList, seedSave, delSeed, getMaterailTypes } = inputSuppliesApi;
|
||||
import { useApp } from '@/hooks';
|
||||
const app = useApp();
|
||||
|
||||
// 查询条件
|
||||
const formInline = reactive({
|
||||
seedName: '',
|
||||
seedTypeId: '',
|
||||
current: 1,
|
||||
size: 10,
|
||||
});
|
||||
const _allTypes = ref([]);
|
||||
watch(
|
||||
() => loadFinish.value,
|
||||
(bol) => {
|
||||
if (bol) {
|
||||
option.value.column.forEach((v) => {
|
||||
if (v.prop === '_classifyId') {
|
||||
_allTypes.value = materialTypes['4'].filter((v, i) => i > 0) ?? [];
|
||||
v.dicData = _allTypes.value;
|
||||
const searchForm = ref(null);
|
||||
const onSubmit = () => {
|
||||
formInline.current = 1;
|
||||
loadData();
|
||||
};
|
||||
const resetForm = () => {
|
||||
searchForm.value.resetFields();
|
||||
};
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
const selectedIds = ref([]);
|
||||
const tableLoading = ref(false);
|
||||
const tableTotal = ref(0);
|
||||
const columns = ref([
|
||||
{ prop: 'seedName', label: '种子种苗名称' },
|
||||
{ prop: 'varietyName', label: '品种名称' },
|
||||
{ prop: 'brand', label: '品牌' },
|
||||
{ prop: 'manufacturer', label: '生产厂家' },
|
||||
{ prop: 'classifyName', label: '分类' },
|
||||
{ prop: 'productUnit', label: '产品规格' },
|
||||
{ prop: 'action', label: '操作', slotName: 'action', width: 230, fixed: 'right' },
|
||||
]);
|
||||
const handlePaginationChange = ({ page, pageSize }) => {
|
||||
formInline.current = page;
|
||||
formInline.size = pageSize;
|
||||
loadData();
|
||||
};
|
||||
const loadData = async () => {
|
||||
tableLoading.value = true;
|
||||
try {
|
||||
let response = await getSeedList(formInline);
|
||||
tableLoading.value = false;
|
||||
if (response.code == 200) {
|
||||
tableData.value = response.data.records;
|
||||
tableTotal.value = response.data.total;
|
||||
}
|
||||
} catch (error) {
|
||||
tableLoading.value = false;
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const extractThirdLevelChildren = (dataArray) => {
|
||||
let result = [];
|
||||
// 遍历第一层数组
|
||||
for (const level1 of dataArray) {
|
||||
// 检查第一层是否有children且是数组
|
||||
if (level1.children && Array.isArray(level1.children)) {
|
||||
// 遍历第二层数组
|
||||
for (const level2 of level1.children) {
|
||||
// 检查第二层是否有children且是数组
|
||||
if (level2.children && Array.isArray(level2.children)) {
|
||||
// 将第三层的所有对象添加到结果数组中
|
||||
result.push(...level2.children);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return result;
|
||||
};
|
||||
const seedTypeChange = () => {
|
||||
console.log(formInline.seedTypeId);
|
||||
// 重新获取表格数据,需添加参数
|
||||
};
|
||||
|
||||
onMounted(getData);
|
||||
/* --------------- data --------------- */
|
||||
// #region
|
||||
const _type = ref('0');
|
||||
const crudRef = ref();
|
||||
const _loading = ref(true);
|
||||
const searchCondition = ref({
|
||||
keywords: '',
|
||||
const dialogFormVisible = ref(false);
|
||||
const dialogRef = ref(null);
|
||||
const dialogTitle = ref('新增');
|
||||
const formDisabled = ref(false);
|
||||
const dialogForm = reactive({
|
||||
id: '',
|
||||
seedName: '', //种子种苗名称
|
||||
varietyName: '', //品种名称
|
||||
brand: '', //品牌
|
||||
manufacturer: '', //生产厂家
|
||||
classifyId: '', //蔬菜种苗id
|
||||
classifyName: '', //蔬菜种苗名称
|
||||
productSpecification: '', //产品规格(number)
|
||||
productUnit: '', //产品规格单位
|
||||
productAttributes: '', //自定义商品属性
|
||||
photoUrl: '', //种子种苗主图
|
||||
photoUrlDetail: '', //种子种苗详情图
|
||||
});
|
||||
const data = ref([]);
|
||||
const option = ref({
|
||||
...CRUD_OPTIONS,
|
||||
selection: false,
|
||||
menuWidth: 160,
|
||||
column: [
|
||||
const dialogFormRules = ref({
|
||||
seedName: [{ required: true, message: '请输入种子种苗名称', trigger: 'blur' }],
|
||||
varietyName: [{ required: true, message: '请输入品种名称', trigger: 'blur' }],
|
||||
brand: [{ required: true, message: '请输入品牌', trigger: 'blur' }],
|
||||
manufacturer: [{ required: true, message: '请输入品牌', trigger: 'blur' }],
|
||||
classifyId: [
|
||||
{
|
||||
label: '种子名称',
|
||||
prop: 'keywords',
|
||||
hide: true,
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '种子名称',
|
||||
prop: 'seedName',
|
||||
rules: customRules({ msg: '请输入种子名称' }),
|
||||
},
|
||||
{
|
||||
prop: 'manufacturer',
|
||||
label: '厂家',
|
||||
rules: customRules({ msg: '请输入厂家名称' }),
|
||||
},
|
||||
{
|
||||
label: '品牌名称',
|
||||
prop: 'brand',
|
||||
rules: customRules({ msg: '请输入品牌名称' }),
|
||||
},
|
||||
{
|
||||
label: '品种名称',
|
||||
prop: 'varietyName',
|
||||
rules: customRules({ msg: '请输入品种名称' }),
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '图片',
|
||||
prop: 'photoUrl',
|
||||
},
|
||||
{
|
||||
label: '分类',
|
||||
prop: '_classifyId',
|
||||
type: 'cascader',
|
||||
expandTrigger: 'click',
|
||||
dicData: [],
|
||||
rules: customRules({ msg: '请选择分类' }),
|
||||
render: ({ row }) => row.classifyName ?? '',
|
||||
},
|
||||
// {
|
||||
// prop: 'distributor',
|
||||
// label: '经销商',
|
||||
// },
|
||||
{
|
||||
prop: 'productUnit',
|
||||
width: '100',
|
||||
label: '产品规格',
|
||||
// editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '种植时间',
|
||||
prop: 'sowingTime',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '种植密度',
|
||||
prop: 'plantDensity',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '施肥管理',
|
||||
prop: 'fertilizeManage',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '水分管理',
|
||||
prop: 'waterManage',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '病虫害防治',
|
||||
prop: 'pestControl',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '注意事项',
|
||||
prop: 'precautions',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
message: '请选择蔬菜种苗',
|
||||
trigger: ['change', 'blur'],
|
||||
},
|
||||
],
|
||||
productUnit: [{ required: true, message: '请输入产品规格', trigger: 'blur' }],
|
||||
});
|
||||
const attrs = ref([]);
|
||||
// #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,
|
||||
seedName: searchCondition.value.keywords,
|
||||
};
|
||||
if (_type.value != '0') params['classifyId'] = _type.value;
|
||||
let res = await getSeedList(params);
|
||||
if (res.code == 200) {
|
||||
data.value = res.data.records ?? [];
|
||||
pageData.value.total = res.data.total;
|
||||
// 新增操作
|
||||
const addItem = async () => {
|
||||
restDialogForm();
|
||||
dialogTitle.value = '新增';
|
||||
formDisabled.value = false;
|
||||
dialogFormVisible.value = true;
|
||||
};
|
||||
// 查看详情
|
||||
const seeDetails = async (row) => {
|
||||
dialogTitle.value = '详情';
|
||||
setDialogForm(row);
|
||||
formDisabled.value = true;
|
||||
dialogFormVisible.value = true;
|
||||
};
|
||||
// 编辑操作
|
||||
const handleEdit = (row) => {
|
||||
console.log('要编辑的行: ', row);
|
||||
dialogTitle.value = '编辑';
|
||||
setDialogForm(row);
|
||||
formDisabled.value = false;
|
||||
dialogFormVisible.value = true;
|
||||
};
|
||||
const setDialogForm = (row) => {
|
||||
dialogForm.id = row.id;
|
||||
dialogForm.seedName = row.seedName;
|
||||
dialogForm.varietyName = row.varietyName;
|
||||
dialogForm.brand = row.brand;
|
||||
dialogForm.manufacturer = row.manufacturer;
|
||||
dialogForm.classifyId = row.classifyId;
|
||||
dialogForm.classifyName = row.classifyName;
|
||||
dialogForm.productSpecification = row.productSpecification;
|
||||
dialogForm.productUnit = row.productUnit;
|
||||
dialogForm.productAttributes = row.productAttributes;
|
||||
dialogForm.photoUrl = row.photoUrl;
|
||||
dialogForm.photoUrlDetail = row.photoUrlDetail;
|
||||
};
|
||||
// 删除操作
|
||||
const handleDelete = (row) => {
|
||||
app
|
||||
.$confirm(`删除后信息将不可查看,确认要删除吗?`, '确定删除', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
})
|
||||
.then(() => {
|
||||
deleteGoods(row.id)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
onSubmit();
|
||||
app.$message.success('删除成功!');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
app.$message.error(err.msg);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
const deleteGoods = async (ids) => {
|
||||
try {
|
||||
let res = await delSeed(ids);
|
||||
return res;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
_loading.value = false;
|
||||
}
|
||||
|
||||
function handleInfo(row) {
|
||||
columnSpanChange(true);
|
||||
handleAttrs(row);
|
||||
crudRef.value.rowView(row);
|
||||
}
|
||||
async function handleRowSave(form, done, loading) {
|
||||
const data = Object.assign({}, form);
|
||||
delete data.keywords;
|
||||
if (attrs.value.length) {
|
||||
data.photoUrl = attrs.value.map((v) => v.url).join();
|
||||
}
|
||||
if (data._classifyId.length) {
|
||||
data.photoUrl = attrs.value.map((v) => v.url).join();
|
||||
}
|
||||
data.classifyId = JSON.stringify(data._classifyId);
|
||||
delete data._classifyId;
|
||||
data.classifyName = targetName(_allTypes.value, form._classifyId, '');
|
||||
let res = await seedSave(data);
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('新增成功');
|
||||
getData();
|
||||
done();
|
||||
}
|
||||
loading();
|
||||
}
|
||||
/* 处理展示附件 */
|
||||
function handleAttrs(row = {}) {
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
if (row.photoUrl) {
|
||||
attrs.value = row.photoUrl.split(',').map((v, i) => {
|
||||
return {
|
||||
url: v,
|
||||
uid: `photo_${i}_${Date.now()}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
function handleCloseDialog(done) {
|
||||
columnSpanChange();
|
||||
attrs.value = [];
|
||||
done();
|
||||
}
|
||||
function columnSpanChange(row = false) {
|
||||
let arr = ['photoUrl'];
|
||||
option.value.column.forEach((v) => {
|
||||
if (arr.includes(v.prop)) {
|
||||
if (row) {
|
||||
v.span = 24;
|
||||
} else {
|
||||
delete v.span;
|
||||
};
|
||||
const onSaveCategory = () => {
|
||||
console.log(dialogForm);
|
||||
dialogRef.value.validate(async (valid, fields) => {
|
||||
if (valid) {
|
||||
try {
|
||||
let param = { ...dialogForm };
|
||||
param.classifyId = dialogForm.classifyId.join(',');
|
||||
param.classifyName = dialogForm.classifyName.join(',');
|
||||
console.log(param);
|
||||
let response;
|
||||
if (dialogTitle.value == '新增') {
|
||||
response = await seedSave(param);
|
||||
} else {
|
||||
response = await seedSave(param);
|
||||
}
|
||||
if (response.code == 200) {
|
||||
cancelDialog();
|
||||
onSubmit();
|
||||
if (dialogTitle.value == '新增') {
|
||||
ElMessage.success('新增成功!');
|
||||
} else {
|
||||
ElMessage.success('编辑成功!');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error(response.msg);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// #endregion
|
||||
</script>
|
||||
};
|
||||
const cancelDialog = async () => {
|
||||
restDialogForm();
|
||||
dialogFormVisible.value = false;
|
||||
};
|
||||
const restDialogForm = () => {
|
||||
Object.assign(dialogForm, {
|
||||
id: '',
|
||||
seedName: '', //种子种苗名称
|
||||
varietyName: '', //品种名称
|
||||
brand: '', //品牌
|
||||
manufacturer: '', //生产厂家
|
||||
classifyId: '', //蔬菜种苗id
|
||||
classifyName: '', //蔬菜种苗名称
|
||||
productSpecification: '', //产品规格(number)
|
||||
productUnit: '', //产品规格单位
|
||||
productAttributes: '', //自定义商品属性
|
||||
photoUrl: '', //种子种苗主图
|
||||
photoUrlDetail: '', //种子种苗详情图
|
||||
});
|
||||
};
|
||||
|
||||
const seedTypeList = ref([]);
|
||||
const seedTypeDialogList = ref([]);
|
||||
const getSeedTypeList = async () => {
|
||||
try {
|
||||
let response = await getMaterailTypes({ moduleType: '4' });
|
||||
console.log(response);
|
||||
if (response.code == 200) {
|
||||
if (response.data?.length > 0) {
|
||||
seedTypeDialogList.value = response.data[0].children;
|
||||
let result = extractThirdLevelChildren(response.data);
|
||||
seedTypeList.value = result;
|
||||
console.log(seedTypeDialogList.value);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
// 级联选择器配置
|
||||
const cascaderProps = ref({
|
||||
label: 'dataName', // 选项标签字段名
|
||||
value: 'id', // 选项值字段名
|
||||
children: 'children', // 子选项字段名
|
||||
emitPath: true,
|
||||
expandTrigger: 'hover',
|
||||
});
|
||||
const handleCascaderChange = () => {
|
||||
const selectedNames = getSelectedNames(dialogForm.classifyId);
|
||||
console.log('对应的名称:', selectedNames); // 例如: ['花草类种子', '具体种子名称']
|
||||
// 如果需要,可以将名称也保存到表单数据中
|
||||
dialogForm.classifyName = selectedNames;
|
||||
};
|
||||
const getSelectedNames = (ids) => {
|
||||
if (!ids || !ids.length) return [];
|
||||
|
||||
let names = [];
|
||||
let currentLevel = seedTypeDialogList.value;
|
||||
|
||||
for (const id of ids) {
|
||||
const foundItem = currentLevel.find((item) => item.id === id);
|
||||
if (!foundItem) break;
|
||||
|
||||
names.push(foundItem.dataName);
|
||||
currentLevel = foundItem.children || [];
|
||||
}
|
||||
|
||||
return names;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
onSubmit();
|
||||
getSeedTypeList();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
font-family: '黑体';
|
||||
.dialog-form-item {
|
||||
:deep(.el-upload--picture-card) {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
:deep(.file-uploader__upload) {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
:deep(.el-upload-list__item) {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,263 @@
|
||||
<template>
|
||||
<section class="custom-page">
|
||||
<h2>种子基本信息</h2>
|
||||
<TypeMenu v-if="materialTypes['4'].length > 1" v-model:type="_type" :types="materialTypes['4']" />
|
||||
<br />
|
||||
<avue-crud
|
||||
ref="crudRef"
|
||||
v-model:page="pageData"
|
||||
v-model:search="searchCondition"
|
||||
:table-loading="_loading"
|
||||
:before-close="handleCloseDialog"
|
||||
:data="data"
|
||||
:option="option"
|
||||
@search-change="
|
||||
(form, done) => {
|
||||
getData(1);
|
||||
done();
|
||||
}
|
||||
"
|
||||
@search-reset="getData(1)"
|
||||
@refresh-change="getData"
|
||||
@current-change="getData"
|
||||
@size-change="getData(1)"
|
||||
@row-save="handleRowSave"
|
||||
>
|
||||
<template #menu="{ row }">
|
||||
<el-button type="primary" @click="handleInfo(row)">详情</el-button>
|
||||
<el-button @click="deleteFn(row.id, delSeed, getData)">删除</el-button>
|
||||
</template>
|
||||
<template #photoUrl-form="{ type }"> <Attrs v-model:attrs="attrs" :type="type == 'add' ? 'add' : 'view'" :limit="2" /> </template>
|
||||
</avue-crud>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch, pushScopeId } from 'vue';
|
||||
import TypeMenu from '../../common/TypeMenu.vue';
|
||||
import { CRUD_OPTIONS, pageData, customRules } from '@/config';
|
||||
import { useBasicInfo } from '@/views/inputSuppliesManage/hooks/useBasicInfo';
|
||||
import Attrs from '@/views/inputSuppliesManage/common/Attrs.vue';
|
||||
import inputSuppliesapi from '@/apis/inputSuppliesApi';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import assistFn from '@/views/inputSuppliesManage/hooks/useAssistFn';
|
||||
const { deleteFn } = new assistFn();
|
||||
const { getSeedList, seedSave, delSeed } = inputSuppliesapi;
|
||||
const { loadFinish, materialTypes, targetName } = useBasicInfo({
|
||||
moduleType: '4',
|
||||
});
|
||||
const _allTypes = ref([]);
|
||||
watch(
|
||||
() => loadFinish.value,
|
||||
(bol) => {
|
||||
if (bol) {
|
||||
option.value.column.forEach((v) => {
|
||||
if (v.prop === '_classifyId') {
|
||||
_allTypes.value = materialTypes['4'].filter((v, i) => i > 0) ?? [];
|
||||
v.dicData = _allTypes.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(getData);
|
||||
/* --------------- data --------------- */
|
||||
// #region
|
||||
const _type = ref('0');
|
||||
const crudRef = ref();
|
||||
const _loading = ref(true);
|
||||
const searchCondition = ref({
|
||||
keywords: '',
|
||||
});
|
||||
const data = ref([]);
|
||||
const option = ref({
|
||||
...CRUD_OPTIONS,
|
||||
selection: false,
|
||||
menuWidth: 160,
|
||||
column: [
|
||||
{
|
||||
label: '种子名称',
|
||||
prop: 'keywords',
|
||||
hide: true,
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
viewDisplay: false,
|
||||
editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '种子名称',
|
||||
prop: 'seedName',
|
||||
rules: customRules({ msg: '请输入种子名称' }),
|
||||
},
|
||||
{
|
||||
prop: 'manufacturer',
|
||||
label: '厂家',
|
||||
rules: customRules({ msg: '请输入厂家名称' }),
|
||||
},
|
||||
{
|
||||
label: '品牌名称',
|
||||
prop: 'brand',
|
||||
rules: customRules({ msg: '请输入品牌名称' }),
|
||||
},
|
||||
{
|
||||
label: '品种名称',
|
||||
prop: 'varietyName',
|
||||
rules: customRules({ msg: '请输入品种名称' }),
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '图片',
|
||||
prop: 'photoUrl',
|
||||
},
|
||||
{
|
||||
label: '分类',
|
||||
prop: '_classifyId',
|
||||
type: 'cascader',
|
||||
expandTrigger: 'click',
|
||||
dicData: [],
|
||||
rules: customRules({ msg: '请选择分类' }),
|
||||
render: ({ row }) => row.classifyName ?? '',
|
||||
},
|
||||
// {
|
||||
// prop: 'distributor',
|
||||
// label: '经销商',
|
||||
// },
|
||||
{
|
||||
prop: 'productUnit',
|
||||
width: '100',
|
||||
label: '产品规格',
|
||||
// editDisplay: false,
|
||||
},
|
||||
{
|
||||
label: '种植时间',
|
||||
prop: 'sowingTime',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '种植密度',
|
||||
prop: 'plantDensity',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '施肥管理',
|
||||
prop: 'fertilizeManage',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '水分管理',
|
||||
prop: 'waterManage',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '病虫害防治',
|
||||
prop: 'pestControl',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
{
|
||||
hide: true,
|
||||
label: '注意事项',
|
||||
prop: 'precautions',
|
||||
span: 24,
|
||||
type: 'textarea',
|
||||
},
|
||||
],
|
||||
});
|
||||
const attrs = ref([]);
|
||||
// #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,
|
||||
seedName: searchCondition.value.keywords,
|
||||
};
|
||||
if (_type.value != '0') params['classifyId'] = _type.value;
|
||||
let res = await getSeedList(params);
|
||||
if (res.code == 200) {
|
||||
data.value = res.data.records ?? [];
|
||||
pageData.value.total = res.data.total;
|
||||
}
|
||||
_loading.value = false;
|
||||
}
|
||||
|
||||
function handleInfo(row) {
|
||||
columnSpanChange(true);
|
||||
handleAttrs(row);
|
||||
crudRef.value.rowView(row);
|
||||
}
|
||||
async function handleRowSave(form, done, loading) {
|
||||
const data = Object.assign({}, form);
|
||||
delete data.keywords;
|
||||
if (attrs.value.length) {
|
||||
data.photoUrl = attrs.value.map((v) => v.url).join();
|
||||
}
|
||||
if (data._classifyId.length) {
|
||||
data.photoUrl = attrs.value.map((v) => v.url).join();
|
||||
}
|
||||
data.classifyId = JSON.stringify(data._classifyId);
|
||||
delete data._classifyId;
|
||||
data.classifyName = targetName(_allTypes.value, form._classifyId, '');
|
||||
let res = await seedSave(data);
|
||||
if (res.code == 200) {
|
||||
ElMessage.success('新增成功');
|
||||
getData();
|
||||
done();
|
||||
}
|
||||
loading();
|
||||
}
|
||||
/* 处理展示附件 */
|
||||
function handleAttrs(row = {}) {
|
||||
if (!row) {
|
||||
return;
|
||||
}
|
||||
if (row.photoUrl) {
|
||||
attrs.value = row.photoUrl.split(',').map((v, i) => {
|
||||
return {
|
||||
url: v,
|
||||
uid: `photo_${i}_${Date.now()}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
function handleCloseDialog(done) {
|
||||
columnSpanChange();
|
||||
attrs.value = [];
|
||||
done();
|
||||
}
|
||||
function columnSpanChange(row = false) {
|
||||
let arr = ['photoUrl'];
|
||||
option.value.column.forEach((v) => {
|
||||
if (arr.includes(v.prop)) {
|
||||
if (row) {
|
||||
v.span = 24;
|
||||
} else {
|
||||
delete v.span;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// #endregion
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
font-family: '黑体';
|
||||
}
|
||||
</style>
|
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div class="custom-page"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, computed } from 'vue';
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="localFormModel" :rules="rules" :disabled="disabled" label-width="120px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地块编号" prop="id">
|
||||
<el-input v-model="localFormModel.id" placeholder="请输入地块编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="面积(亩)" prop="area">
|
||||
<el-input-number v-model="localFormModel.area" :min="0" placeholder="请输入面积" />
|
||||
</el-form-item>
|
||||
<el-form-item label="所属行政区域" prop="areaCode">
|
||||
<AreaSelect v-model="localFormModel.areaCode" :emit-path="false" label="" />
|
||||
</el-form-item>
|
||||
<el-form-item label="经营主体编码" prop="businessSubjectCode">
|
||||
<el-input v-model="localFormModel.businessSubjectCode" placeholder="请输入经营主体编码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="种植开始时间" prop="plantingStartTime">
|
||||
<el-date-picker v-model="localFormModel.plantingStartTime" type="date" placeholder="请选择种植开始时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="账号(手机号)" prop="account">
|
||||
<el-input v-model="localFormModel.account" placeholder="请输入账号(手机号)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="信息审核时间" prop="auditTime">
|
||||
<el-date-picker v-model="localFormModel.auditTime" type="date" placeholder="请选择信息审核时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地块名称" prop="landName">
|
||||
<el-input v-model="localFormModel.landName" placeholder="请输入地块名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="具体位置" prop="address">
|
||||
<el-input v-model="localFormModel.address" placeholder="请输入具体位置" />
|
||||
</el-form-item>
|
||||
<el-form-item label="种植作物" prop="CropName">
|
||||
<el-input v-model="localFormModel.CropName" placeholder="请输入种植作物" />
|
||||
</el-form-item>
|
||||
<el-form-item label="作物品种" prop="CropVarietyName">
|
||||
<el-input v-model="localFormModel.CropVarietyName" placeholder="请输入作物品种" />
|
||||
</el-form-item>
|
||||
<el-form-item label="种植结束时间" prop="plantingEndTime">
|
||||
<el-date-picker v-model="localFormModel.plantingEndTime" type="date" placeholder="请选择种植结束时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="经营主体名称" prop="businessSubjectName">
|
||||
<el-input v-model="localFormModel.businessSubjectName" placeholder="请输入经营主体名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="信息填报时间" prop="fillTime">
|
||||
<el-date-picker v-model="localFormModel.fillTime" type="date" placeholder="请选择信息填报时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const localFormModel = ref({ ...props.modelValue });
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val) {
|
||||
localFormModel.value = { ...val };
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
localFormModel,
|
||||
(val) => {
|
||||
emit('update:modelValue', val);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const rules = {
|
||||
// id: [{ required: true, message: '地块编号不能为空', trigger: 'blur' }],
|
||||
// area: [{ type: 'number', min: 0, message: '面积必须大于等于0', trigger: 'change' }],
|
||||
};
|
||||
</script>
|
@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div class="custom-body">
|
||||
<SearchBar v-model:search="searchForm" @search="handleSearch" @reset="handleReset" />
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabChange">
|
||||
<!-- <el-tab-pane label="待提交" name="-1" /> -->
|
||||
<el-tab-pane label="待审核" name="0" />
|
||||
<el-tab-pane label="已通过" name="1" />
|
||||
<el-tab-pane label="已驳回" name="2" />
|
||||
</el-tabs>
|
||||
<avue-crud
|
||||
ref="crudRef"
|
||||
v-model:page="pagination"
|
||||
:data="crudData"
|
||||
:option="crudOptions"
|
||||
:table-loading="loading"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange"
|
||||
>
|
||||
<template #menu="scope">
|
||||
<custom-table-operate :actions="getActions(scope.row)" :data="scope" />
|
||||
</template>
|
||||
</avue-crud>
|
||||
<el-dialog v-model="visible" title="查看" width="60%" align-center :draggable="true">
|
||||
<RecordForm ref="formRef" v-model="formData" :disabled="mode === 'view'" />
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<el-button v-if="mode !== 'view'" type="primary" @click="handleSubmit">提交</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch, onMounted } from 'vue';
|
||||
import SearchBar from './SearchBar.vue';
|
||||
import { CRUD_OPTIONS } from '@/config';
|
||||
import RecordForm from './RecordForm.vue';
|
||||
|
||||
const loading = ref(false);
|
||||
const visible = ref(false);
|
||||
|
||||
const searchForm = ref({
|
||||
status: 1,
|
||||
keyword: '',
|
||||
regionCode: '',
|
||||
gridId: '',
|
||||
landTypeId: '',
|
||||
});
|
||||
|
||||
const activeTab = ref('1');
|
||||
const handleTabChange = ({ name }) => {
|
||||
getData();
|
||||
};
|
||||
|
||||
const pagination = ref({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
const crudData = ref([]);
|
||||
const crudOptions = reactive({
|
||||
...CRUD_OPTIONS,
|
||||
header: false,
|
||||
height: 'calc(100vh - 330px)',
|
||||
column: [
|
||||
{ label: '地块编号', prop: 'landNumber', width: 160 },
|
||||
{ label: '地块名称', prop: 'landName', width: 170 },
|
||||
{ label: '面积', prop: 'planArea', formatter: (row, column, cellValue) => `${Number(cellValue).toFixed(2)} 亩` },
|
||||
{ label: '所属行政区域', prop: 'belongRegion', width: 160 },
|
||||
{ label: '所属网格', prop: 'belongGrid', width: 90 },
|
||||
{ label: '具体位置', prop: 'address', width: 160 },
|
||||
{ label: '基地名称', prop: 'baseName' },
|
||||
{ label: '种植批次编码', prop: 'batchCode' },
|
||||
{ label: '种植批次名称', prop: 'batchName' },
|
||||
{ label: '种植作物', prop: 'crop' },
|
||||
{ label: '作物品种', prop: 'cropBrand' },
|
||||
{ label: '种植开始时间', prop: 'startDate' },
|
||||
{ label: '种植结束时间', prop: 'endDate' },
|
||||
{ label: '经营主体代码', prop: 'businessEntityCode', width: 130 },
|
||||
{ label: '经营主体类型', prop: 'businessEntityType', width: 130 },
|
||||
{ label: '经营主体名称', prop: 'businessEntityName', width: 130 },
|
||||
{ label: '账号(手机号)', prop: 'account', width: 130 },
|
||||
{ label: '信息填报时间', prop: 'fillTime', width: 110 },
|
||||
{ label: '信息审核时间', prop: 'approvalTime', width: 110 },
|
||||
],
|
||||
});
|
||||
const handleCurrentChange = (val) => {
|
||||
pagination.value.currentPage = val;
|
||||
};
|
||||
const handleSizeChange = (val) => {
|
||||
pagination.value.pageSize = val;
|
||||
};
|
||||
|
||||
const getActions = (row) => {
|
||||
return [{ name: '查看', icon: 'view', event: () => handleView(row) }];
|
||||
};
|
||||
const formRef = ref();
|
||||
const formData = ref({}); // 初始数据
|
||||
const mode = ref('view'); // 或 'edit' / 'create'
|
||||
const handleView = (row) => {
|
||||
formData.value = { ...row };
|
||||
mode.value = 'view';
|
||||
visible.value = true;
|
||||
};
|
||||
const handleSearch = () => {};
|
||||
const handleReset = () => {
|
||||
getData();
|
||||
};
|
||||
|
||||
import { mockData } from '../mockData';
|
||||
import { createRecord, deleteRecord, updateRecord, getRecord, fetchRecordList } from '@/apis/inputSuppliesApi/record';
|
||||
const getData = async () => {
|
||||
loading.value = true;
|
||||
searchForm.value.status = Number(activeTab.value);
|
||||
// 调用接口获取数据
|
||||
const response = await fetchRecordList(searchForm.value);
|
||||
crudData.value = response.data.records;
|
||||
pagination.value.total = response.data.total;
|
||||
loading.value = false;
|
||||
// setTimeout(() => {
|
||||
// crudData.value = mockData.filter((item) => item.landStatus === Number(activeTab.value));
|
||||
// pagination.value.total = crudData.value.length;
|
||||
// loading.value = false;
|
||||
// }, 200);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 20px;
|
||||
height: calc(100vh - 300px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="custom-page-search">
|
||||
<el-form :model="search" inline label-width="100px">
|
||||
<el-form-item label="关键词搜索" prop="keyword">
|
||||
<el-input v-model="search.keyword" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0px">
|
||||
<AreaCascader v-model:region-code="search.regionCode" v-model:grid-id="search.gridId" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="种植作物" prop="planCrop">
|
||||
<url-select
|
||||
v-model="search.planCrop"
|
||||
url="/land-resource/crops/page"
|
||||
:params="{ status: '0' }"
|
||||
label-key="cropsName"
|
||||
value-key="id"
|
||||
placeholder="请选择种植作物"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSearch">搜索</el-button>
|
||||
<el-button @click="onReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch, toRefs } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
search: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:search', 'search', 'reset']);
|
||||
|
||||
const search = reactive({ ...props.search });
|
||||
|
||||
watch(
|
||||
search,
|
||||
(val) => {
|
||||
emit('update:search', { ...val });
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const onSearch = () => {
|
||||
emit('search');
|
||||
};
|
||||
|
||||
const onReset = () => {
|
||||
Object.keys(search).forEach((key) => {
|
||||
search[key] = '';
|
||||
});
|
||||
emit('update:search', { ...search });
|
||||
emit('reset');
|
||||
};
|
||||
</script>
|
@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div class="custom-page">
|
||||
<RecordPage />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import RecordPage from './components/RecordPage.vue';
|
||||
</script>
|
@ -0,0 +1,537 @@
|
||||
<template>
|
||||
<div class="custom-page">
|
||||
<h1>农产品种植品种备案</h1>
|
||||
<!-- 搜索 -->
|
||||
<el-form :inline="true" :model="searchForm" class="search-bar">
|
||||
<el-form-item label="关键词">
|
||||
<el-input v-model="searchForm.name" placeholder="请输入关键词" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item lable="">
|
||||
<AreaCascader v-model:region-code="searchForm.regionCode" v-model:grid-id="searchForm.gridId" :width="600" />
|
||||
</el-form-item>
|
||||
<el-form-item label="种植作物">
|
||||
<url-select
|
||||
v-model="searchForm.cropId"
|
||||
placeholder="选择种植作物"
|
||||
url="/land-resource/baseInfo/cropPage"
|
||||
:params="{ current: 1, size: 100 }"
|
||||
label-key="cropName"
|
||||
value-key="id"
|
||||
:clearable="true"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch"> 搜索 </el-button>
|
||||
<el-button @click="resetSearch"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 四个固定 Tabs -->
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabChange">
|
||||
<!-- <el-tab-pane label="待提交" name="-1" /> -->
|
||||
<el-tab-pane label="待审核" name="0" />
|
||||
<el-tab-pane label="已通过" name="1" />
|
||||
<el-tab-pane label="已驳回" name="2" />
|
||||
</el-tabs>
|
||||
<avue-crud
|
||||
ref="crudRef"
|
||||
v-model:page="pageData"
|
||||
:data="crudData"
|
||||
:option="crudOptions"
|
||||
:table-loading="loading"
|
||||
@current-change="handleCurrentChange"
|
||||
@size-change="handleSizeChange"
|
||||
>
|
||||
<template #menu="scope">
|
||||
<custom-table-operate :actions="crudOptions.actions" :data="scope" />
|
||||
</template>
|
||||
</avue-crud>
|
||||
<el-dialog :key="dialogTitle" v-model="visible" :title="dialogTitle" width="60%" align-center :draggable="true">
|
||||
<el-tabs v-model="activeFormTab" class="tabs-wrapper">
|
||||
<el-tab-pane label="土地基本信息" name="basic">
|
||||
<p class="form-title">基本信息</p>
|
||||
<el-form ref="basicFormRef" :model="formData" :disabled="isReadonly" label-width="120px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地块名称" prop="landName">
|
||||
<el-input v-model="formData.landName" placeholder="请输入地块名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="土地类型" prop="landType">
|
||||
<el-tree-select
|
||||
v-model="formData.landType"
|
||||
:data="landTypeOptions"
|
||||
:props="treeProps"
|
||||
placeholder="选择土地类型"
|
||||
clearable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
@change="handleLandTypeChange"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="具体位置" prop="address">
|
||||
<el-input v-model="formData.address" placeholder="请输入具体位置" />
|
||||
</el-form-item>
|
||||
<el-form-item label="土壤类型" prop="soilTypeId">
|
||||
<url-select
|
||||
v-model="formData.soilTypeId"
|
||||
placeholder="选择土壤类型"
|
||||
url="/land-resource/baseInfo/soilTypePage"
|
||||
:params="{ current: 1, size: 100 }"
|
||||
label-key="soilType"
|
||||
value-key="id"
|
||||
:clearable="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="土地照片" prop="landUrl">
|
||||
<FileUploader v-model="formData.landUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="面积(亩)" prop="area">
|
||||
<el-input-number v-model="formData.area" :min="0" :precision="2" :step="0.1" controls-position="right" style="width: 100%" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="" label-width="0" prop="gridId">
|
||||
<AreaCascader v-model:region-code="formData.gridAreaCode" v-model:grid-id="formData.gridId" label="" :split-rows="true" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="土地范围" prop="scope">
|
||||
<el-input v-model="formData.scope" placeholder="请输入土地范围" />
|
||||
<!-- <Attrs v-model:attrs="formData.scope" type="add" accept="image/*" /> -->
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="土地承包信息" name="property">
|
||||
<p class="form-title">承包信息</p>
|
||||
<el-form ref="propertyFormRef" :model="formData" :disabled="isReadonly" label-width="150px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="土地承包经营权人" prop="propertyName">
|
||||
<el-input v-model="formData.propertyName" placeholder="请输入产权人姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系方式" prop="propertyPhone">
|
||||
<el-input v-model="formData.propertyPhone" placeholder="请输入产权人联系方式" />
|
||||
</el-form-item>
|
||||
<el-form-item label="土地经营权证书编号" prop="landCode">
|
||||
<el-input v-model="formData.landCode" placeholder="请输入产权编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="土地经营权证书" prop="propertyCertificateUrl">
|
||||
<FileUploader v-model="formData.propertyCertificateUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :span="12"></el-col> -->
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="土地流转信息" name="use">
|
||||
<p class="form-title">流转信息</p>
|
||||
<el-form ref="useForm" :model="formData" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否土地流转" prop="landTransfer">
|
||||
<el-radio-group v-model="formData.landTransfer" :disabled="isReadonly">
|
||||
<el-radio label="1">是</el-radio>
|
||||
<el-radio label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.landTransfer === '1'" label="土地受让方" prop="landUseName">
|
||||
<el-input v-model="formData.landUseName" placeholder="请输入土地受让方" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.landTransfer === '1'" label="联系电话" prop="landUsePhone">
|
||||
<el-input v-model="formData.landUsePhone" placeholder="请输入土地受让方联系方式" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.landTransfer === '1'" label="流转合同" prop="landCertificateUrl">
|
||||
<FileUploader v-model="formData.landCertificateUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
<template v-if="!isReadonly">
|
||||
<el-button type="primary" @click="submitAll">修改</el-button>
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// ---------------------------------------------------------------------
|
||||
// avue-crud 通用代码
|
||||
// ---------------------------------------------------------------------
|
||||
import { ref, reactive, watch, onMounted, computed, nextTick } from 'vue';
|
||||
import { CRUD_OPTIONS } from '@/config';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import request from '@/utils/axios';
|
||||
|
||||
const UserStore = useUserStore();
|
||||
const user = UserStore.getUserInfo();
|
||||
console.log('admin 属性:', user.admin);
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
const visible = ref(false);
|
||||
const isReadonly = ref(false);
|
||||
const dialogTitle = ref();
|
||||
const activeTab = ref('1');
|
||||
const activeFormTab = ref('basic');
|
||||
const formData = ref({
|
||||
gridName: '',
|
||||
gridAreaCode: '',
|
||||
scope: '',
|
||||
scopeImg: '',
|
||||
note: '',
|
||||
});
|
||||
const initialFormData = { ...formData.value };
|
||||
const resetForm = () => {
|
||||
formData.value = { ...initialFormData };
|
||||
};
|
||||
|
||||
const pageData = ref({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
const searchForm = ref({
|
||||
keyword: '',
|
||||
landStatus: 1,
|
||||
regionCode: '',
|
||||
gridId: '',
|
||||
id: '',
|
||||
landTypeName: '草地',
|
||||
});
|
||||
const initialSearchForm = { ...searchForm.value };
|
||||
const resetSearch = () => {
|
||||
searchForm.value = { ...initialSearchForm };
|
||||
};
|
||||
// 过滤对象,只保留有值的属性
|
||||
const filterObject = (obj) => {
|
||||
const newObj = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const value = obj[key];
|
||||
// 检查值是否有效,排除空字符串、null 和 undefined
|
||||
if (value !== '' && value !== null && value !== undefined) {
|
||||
newObj[key] = value;
|
||||
}
|
||||
});
|
||||
return newObj;
|
||||
};
|
||||
|
||||
const crudData = ref([]);
|
||||
const crudOptions = reactive({
|
||||
...CRUD_OPTIONS,
|
||||
addBtn: false,
|
||||
header: false,
|
||||
searchBtn: false,
|
||||
emptyBtn: false,
|
||||
refreshBtn: false,
|
||||
height: 'calc(100vh - 360px)',
|
||||
column: [
|
||||
{ label: '地块编号', prop: 'id', width: 160 },
|
||||
{ label: '地块名称', prop: 'landName', width: 170 },
|
||||
{ label: '面积', prop: 'area', formatter: (row, column, cellValue) => `${Number(cellValue).toFixed(2)} 亩` },
|
||||
{ label: '所属行政区域', prop: 'fullRegionName', width: 160 },
|
||||
{ label: '所属网格', prop: 'gridName', width: 90 },
|
||||
{ label: '具体位置', prop: 'address', width: 160 },
|
||||
{ label: '种植作物', prop: 'CropName' },
|
||||
{ label: '作物品种', prop: 'CropVarietyName' },
|
||||
{ label: '种植开始时间', prop: 'plantingStartTime' },
|
||||
{ label: '种植结束时间', prop: 'plantingEndTime' },
|
||||
{ label: '经营主体名称', prop: 'businessSubjectName', width: 130 },
|
||||
{ label: '账号(手机号)', prop: ' account', width: 130 },
|
||||
{ label: '信息填报时间', prop: 'fillTime', width: 110 },
|
||||
{ label: '信息审核时间', prop: 'auditTime', width: 110 },
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
name: '查看',
|
||||
icon: 'view',
|
||||
event: ({ row }) => handleView(row),
|
||||
},
|
||||
{
|
||||
name: '编辑',
|
||||
icon: 'edit',
|
||||
event: ({ row }) => handleEdit(row),
|
||||
},
|
||||
{
|
||||
type: 'danger',
|
||||
name: '删除',
|
||||
icon: 'delete',
|
||||
event: ({ row }) => handleDelete(row),
|
||||
},
|
||||
{
|
||||
name: '审核',
|
||||
icon: 'approve',
|
||||
event: ({ row }) => onApprove(row),
|
||||
},
|
||||
// TODO: 驳回应该有填写驳回原因的弹窗
|
||||
{
|
||||
name: '驳回',
|
||||
icon: 'reject',
|
||||
event: ({ row }) => onReject(row),
|
||||
},
|
||||
{
|
||||
name: '驳回原因',
|
||||
icon: 'reject',
|
||||
event: ({ row }) => onRejectReason(row),
|
||||
},
|
||||
],
|
||||
});
|
||||
const handleTabChange = ({ name }) => {
|
||||
searchForm.value.landStatus = Number(activeTab.value);
|
||||
getData();
|
||||
};
|
||||
const handleRefresh = async () => {
|
||||
searchForm.value = { ...initialSearchForm };
|
||||
getData();
|
||||
};
|
||||
const handleCurrentChange = (val) => {
|
||||
pageData.value.currentPage = val;
|
||||
};
|
||||
const handleSizeChange = (val) => {
|
||||
pageData.value.pageSize = val;
|
||||
};
|
||||
const handleView = async (row) => {
|
||||
isReadonly.value = true;
|
||||
formData.value = await getLandDetail(row.id);
|
||||
dialogTitle.value = '查看网格';
|
||||
visible.value = true;
|
||||
};
|
||||
const handleEdit = (row) => {
|
||||
isReadonly.value = false;
|
||||
formData.value = { ...row };
|
||||
dialogTitle.value = '编辑网格';
|
||||
visible.value = true;
|
||||
};
|
||||
const handleDelete = async (row) => {
|
||||
console.log('删除', row);
|
||||
// try {
|
||||
// await ElMessageBox.confirm('确认删除该网格吗?', '提示', {
|
||||
// confirmButtonText: '确定',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning',
|
||||
// });
|
||||
|
||||
// const response = await deleteGrid(row.id);
|
||||
|
||||
// ElMessage.success('删除成功');
|
||||
// getData();
|
||||
// } catch (error) {
|
||||
// if (error === 'cancel') {
|
||||
// ElMessage.info('已取消删除');
|
||||
// } else {
|
||||
// ElMessage.error('删除失败');
|
||||
// console.error('删除异常:', error);
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
console.log('提交表单:', formData.value);
|
||||
try {
|
||||
if (dialogTitle.value === '新增网格') {
|
||||
await createLand(formData.value);
|
||||
ElMessage.success('新增成功');
|
||||
resetForm();
|
||||
visible.value = false;
|
||||
getData();
|
||||
} else {
|
||||
await editLand(formData.value);
|
||||
ElMessage.success('更新成功');
|
||||
resetForm();
|
||||
visible.value = false;
|
||||
getData();
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message || '新增失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 业务代码
|
||||
// ---------------------------------------------------------------------
|
||||
import { createLand, deleteLand, editLand, fetchLandList, getLandById, approveLand } from '@/apis/landResourceManagement/landManagement';
|
||||
|
||||
onMounted(() => {
|
||||
getData();
|
||||
fetchLandTypeData();
|
||||
});
|
||||
const getData = async () => {
|
||||
loading.value = true;
|
||||
const filteredParams = filterObject(searchForm.value);
|
||||
const response = await fetchLandList(filteredParams);
|
||||
crudData.value = Array.isArray(response.data.records) ? response.data.records : [];
|
||||
pageData.value.total = crudData.value.length;
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const getLandDetail = async (id) => {
|
||||
const response = await getLandById(id);
|
||||
return response.data;
|
||||
};
|
||||
const landTypeOptions = ref([]);
|
||||
const treeProps = ref({
|
||||
value: 'id',
|
||||
label: 'landType',
|
||||
children: 'children',
|
||||
// disabled: (data) => {
|
||||
// return data.children && data.children.length > 0;
|
||||
// },
|
||||
});
|
||||
const fetchLandTypeData = async () => {
|
||||
try {
|
||||
const response = await request.get('/land-resource/baseInfo/landTree', { params: { status: '1' } });
|
||||
if (response.code === 200) {
|
||||
landTypeOptions.value = response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取土地类型数据失败', error);
|
||||
}
|
||||
};
|
||||
const submitAll = async () => {
|
||||
console.log('提交表单:', formData.value);
|
||||
await editLand(formData.value);
|
||||
ElMessage.success('保存成功');
|
||||
resetForm();
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const onApprove = async (row) => {
|
||||
// UNSUBMIT(-1,"未提交"),
|
||||
// REVIEW(0,"待审核"),
|
||||
// PASS(1,"通过"),
|
||||
// REFUSE(2,"驳回");
|
||||
if (row.landStatus !== 0) {
|
||||
ElMessage.error('该地块状态不是待审核状态');
|
||||
return;
|
||||
}
|
||||
const requiredBody = {
|
||||
bizType: 'landResInfo',
|
||||
bizId: row.id,
|
||||
status: 1,
|
||||
opinion: '',
|
||||
};
|
||||
await approveLand(requiredBody);
|
||||
ElMessage.success('审核成功');
|
||||
getData();
|
||||
};
|
||||
|
||||
const onReject = async (row) => {
|
||||
if (row.landStatus !== 0) {
|
||||
ElMessage.error('该地块状态不是待审核状态');
|
||||
return;
|
||||
}
|
||||
const requiredBody = {
|
||||
bizType: 'landResInfo',
|
||||
bizId: row.id,
|
||||
status: 2,
|
||||
opinion: '',
|
||||
};
|
||||
await approveLand(requiredBody);
|
||||
ElMessage.success('驳回成功');
|
||||
getData();
|
||||
};
|
||||
// 显示驳回原因
|
||||
const onRejectReason = async (row) => {
|
||||
ElMessageBox.alert(row.rejectReason || '无驳回原因', '驳回原因');
|
||||
};
|
||||
const handleAdd = () => {
|
||||
console.log('handleAdd');
|
||||
resetForm();
|
||||
isReadonly.value = false;
|
||||
dialogTitle.value = '新增网格';
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
getData();
|
||||
};
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-page {
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.search-bar {
|
||||
padding-left: 20px;
|
||||
}
|
||||
:deep(.el-dialog__body) {
|
||||
padding: 20px;
|
||||
// height: calc(100vh - 300px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.form-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin: 30px 0;
|
||||
color: #333333;
|
||||
}
|
||||
.form-item {
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.dialog-footer {
|
||||
text-align: center;
|
||||
}
|
||||
.custom-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 20px;
|
||||
|
||||
.el-button {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
.tabs-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// background-color: #7daaaa;
|
||||
|
||||
.el-tabs__header {
|
||||
width: 100%;
|
||||
|
||||
.el-tabs__nav-scroll {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
font-size: 16px;
|
||||
color: #555555;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
:deep(.el-tabs__content) {
|
||||
padding: 20px;
|
||||
// background-color: #af8686;
|
||||
border-radius: 4px;
|
||||
width: 80%;
|
||||
height: calc(100vh - 400px);
|
||||
overflow-y: auto;
|
||||
|
||||
.el-tab-pane {
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
// background-color: #555555;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,87 @@
|
||||
export const mockData = [
|
||||
{
|
||||
id: 'LD20230001',
|
||||
landName: '阳光农场1号地',
|
||||
area: 120.5,
|
||||
fullRegionName: '浙江省杭州市余杭区',
|
||||
gridName: '网格A',
|
||||
address: '余杭区五常街道阳光路1号',
|
||||
CropName: '水稻',
|
||||
CropVarietyName: '超级稻',
|
||||
plantingStartTime: '2023-04-10',
|
||||
plantingEndTime: '2023-09-20',
|
||||
businessSubjectName: '杭州阳光农业有限公司',
|
||||
account: '13800138001',
|
||||
fillTime: '2023-04-05 10:30',
|
||||
auditTime: '', // 待审核状态没有审核时间
|
||||
landStatus: 0, // 0=待审核
|
||||
},
|
||||
{
|
||||
id: 'LD20230002',
|
||||
landName: '绿洲农场2号地',
|
||||
area: 85.2,
|
||||
fullRegionName: '浙江省杭州市西湖区',
|
||||
gridName: '网格B',
|
||||
address: '西湖区转塘街道绿洲路2号',
|
||||
CropName: '小麦',
|
||||
CropVarietyName: '冬小麦',
|
||||
plantingStartTime: '2023-03-15',
|
||||
plantingEndTime: '2023-07-25',
|
||||
businessSubjectName: '杭州绿洲农业合作社',
|
||||
account: '13900139002',
|
||||
fillTime: '2023-03-10 14:20',
|
||||
auditTime: '2023-03-12 09:15', // 已通过有审核时间
|
||||
landStatus: 1, // 1=已通过
|
||||
},
|
||||
{
|
||||
id: 'LD20230003',
|
||||
landName: '丰收农场3号地',
|
||||
area: 200.0,
|
||||
fullRegionName: '浙江省杭州市萧山区',
|
||||
gridName: '网格C',
|
||||
address: '萧山区宁围街道丰收路3号',
|
||||
CropName: '玉米',
|
||||
CropVarietyName: '甜玉米',
|
||||
plantingStartTime: '2023-05-01',
|
||||
plantingEndTime: '2023-10-30',
|
||||
businessSubjectName: '萧山丰收农业有限公司',
|
||||
account: '13700137003',
|
||||
fillTime: '2023-04-28 16:45',
|
||||
auditTime: '2023-04-30 11:00', // 已驳回有审核时间
|
||||
landStatus: 2, // 2=已驳回
|
||||
},
|
||||
{
|
||||
id: 'LD20230004',
|
||||
landName: '试验田4号地',
|
||||
area: 50.8,
|
||||
fullRegionName: '浙江省杭州市滨江区',
|
||||
gridName: '网格D',
|
||||
address: '滨江区长河街道试验田路4号',
|
||||
CropName: '大豆',
|
||||
CropVarietyName: '转基因大豆',
|
||||
plantingStartTime: '2023-06-01',
|
||||
plantingEndTime: '2023-11-15',
|
||||
businessSubjectName: '滨江农业研究所',
|
||||
account: '13600136004',
|
||||
fillTime: '2023-05-25 09:10',
|
||||
auditTime: '', // 待审核状态没有审核时间
|
||||
landStatus: 0, // 0=待审核
|
||||
},
|
||||
{
|
||||
id: 'LD20230005',
|
||||
landName: '有机农场5号地',
|
||||
area: 180.3,
|
||||
fullRegionName: '浙江省杭州市临安区',
|
||||
gridName: '网格E',
|
||||
address: '临安区青山湖街道有机路5号',
|
||||
CropName: '蔬菜',
|
||||
CropVarietyName: '有机菠菜',
|
||||
plantingStartTime: '2023-02-20',
|
||||
plantingEndTime: '2023-12-31',
|
||||
businessSubjectName: '临安有机农业有限公司',
|
||||
account: '13500135005',
|
||||
fillTime: '2023-02-15 13:25',
|
||||
auditTime: '2023-02-18 10:30', // 已通过有审核时间
|
||||
landStatus: 1, // 1=已通过
|
||||
},
|
||||
];
|
@ -2,7 +2,7 @@
|
||||
<section class="custom-page">
|
||||
<!-- 四个固定 Tabs -->
|
||||
<el-tabs v-model="activeCrudTab" @tab-click="handleTabChange">
|
||||
<el-tab-pane label="待提交" name="0" />
|
||||
<!-- <el-tab-pane label="待提交" name="0" /> -->
|
||||
<el-tab-pane label="待审核" name="1" />
|
||||
<el-tab-pane label="已通过" name="2" />
|
||||
<el-tab-pane label="已驳回" name="3" />
|
||||
@ -60,7 +60,7 @@ import { getEnterList, getEnterById, addEnter, updateEnter, approvalEnter, delet
|
||||
|
||||
// 控制弹窗显示
|
||||
const visible = ref(false);
|
||||
const activeCrudTab = ref('0');
|
||||
const activeCrudTab = ref('1');
|
||||
const activeTab = ref('basic');
|
||||
const dialogTitle = ref('新增');
|
||||
const isReadonly = ref(false);
|
||||
@ -173,13 +173,19 @@ const crudOptions = reactive({
|
||||
searchBtn: false,
|
||||
emptyBtn: false,
|
||||
column: [
|
||||
{ label: '生产经营主体编码', prop: 'id' },
|
||||
{ label: '企业名称', prop: 'businessName' },
|
||||
{ label: '所属行政区划', prop: 'address' },
|
||||
{ label: '企业负责人', prop: 'contactPerson' },
|
||||
{ label: '联系方式', prop: 'phone' },
|
||||
{ label: '企业地址', prop: 'address' },
|
||||
{ label: '地块数量', prop: 'villageCount' },
|
||||
{ label: '地块编号', prop: 'villageCode' },
|
||||
{ label: '地块名称', prop: 'villageName' },
|
||||
{ label: '面积', prop: 'area', formatter: (row, column, cellValue) => `${Number(cellValue).toFixed(2)} 亩` },
|
||||
{ label: '经营产品', prop: 'businessScope' },
|
||||
{ label: '联系人', prop: 'contactPerson' },
|
||||
{ label: '联系电话', prop: 'phone' },
|
||||
// { label: '聘工人数', prop: 'villageCount' },
|
||||
{ label: '所属行政区划', prop: 'address' },
|
||||
{ label: '所属网格', prop: 'gridCode' },
|
||||
{ label: '种植作物', prop: 'primaryProduct' },
|
||||
{ label: '账号(手机号)', prop: 'account' },
|
||||
{ label: '信息录入时间', prop: 'createTime' },
|
||||
{ label: '信息更新时间', prop: 'updateTime' },
|
||||
],
|
||||
|
@ -1,712 +0,0 @@
|
||||
<template>
|
||||
<div class="custom-page">
|
||||
<avue-crud ref="crudRef" v-model:page="pageData" :data="filteredData" :option="crudOptions" :table-loading="loading">
|
||||
<template #menu-left>
|
||||
<!-- <el-button type="primary" icon="Upload" @click="onImport">导入</el-button> -->
|
||||
<el-button type="danger" icon="Delete" @click="onBatchDel">批量删除</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, h } from 'vue';
|
||||
import { useApp } from '@/hooks';
|
||||
import { CRUD_OPTIONS } from '@/config';
|
||||
import { isEmpty, downloadFile } from '@/utils';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import {
|
||||
getOperationRecord,
|
||||
saveOperationRecord,
|
||||
editOperationRecord,
|
||||
delOperationRecord,
|
||||
exportOperationRecord,
|
||||
getAddrCropByLand,
|
||||
importOperationRecord,
|
||||
} from '@/apis/land';
|
||||
import uploadImg from '../components/uploadImg.vue';
|
||||
|
||||
const { VITE_APP_BASE_API } = import.meta.env;
|
||||
const app = useApp();
|
||||
const UserStore = useUserStore();
|
||||
const crudRef = ref(null);
|
||||
const handleLandChange = async (value, form, done) => {
|
||||
if (!value || !value.item || !value.item.id) return; // 如果没有选择任何地块,则直接返回
|
||||
let val = {};
|
||||
getAddrCropByLand(value.item?.id || '')
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
val = res.data || {};
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
val = {};
|
||||
})
|
||||
.finally(() => {});
|
||||
state.form.crop = val?.crop || value.item?.crop;
|
||||
state.form.address = val?.county + val?.town + val?.village || value.item?.address;
|
||||
};
|
||||
|
||||
const productTypeOptions = reactive([
|
||||
{ label: '蔬菜', value: '0' },
|
||||
{ label: '水果', value: '1' },
|
||||
{ label: '畜产品', value: '2' },
|
||||
{ label: '水产品', value: '3' },
|
||||
{ label: '谷物', value: '4' },
|
||||
{ label: '农资', value: '5' },
|
||||
{ label: '种源', value: '6' },
|
||||
{ label: '农产品加工', value: '7' },
|
||||
{ label: '其他', value: '8' },
|
||||
]);
|
||||
|
||||
const bTypeOptions = reactive([
|
||||
{ label: '农户', value: '0' },
|
||||
// { label: '种植', value: '1' },
|
||||
{ label: '合作社', value: '2' },
|
||||
]);
|
||||
|
||||
let timeVal = ref([]);
|
||||
const licenseImg = ref('');
|
||||
const permitImg = ref('');
|
||||
const data = reactive([
|
||||
{
|
||||
crop1: '100001',
|
||||
crop2: '耿马佑氏种植专业合作社',
|
||||
crop3: '蔬菜',
|
||||
crop4: '>20人',
|
||||
crop5: '云南省临沧市耿马县耿马镇城区甘东村允楞芒抗山',
|
||||
crop6: '何仙义',
|
||||
crop7: '18008834114',
|
||||
crop8: '93530926MA6K3M3K5U',
|
||||
crop9: '图片',
|
||||
crop10: '无固定期限',
|
||||
crop11: '已通过',
|
||||
crop12: '暂无',
|
||||
crop13: '2025-03-01',
|
||||
},
|
||||
{
|
||||
crop1: '100002',
|
||||
crop2: '耿马金田园种植专业合作社',
|
||||
crop3: '蔬菜',
|
||||
crop4: '>20人',
|
||||
crop5: '云南省临沧市耿马县四排山公路6公里处',
|
||||
crop6: '董福良',
|
||||
crop7: '13578302599',
|
||||
crop8: '93530926MA6N6C4N8U',
|
||||
crop9: '图片',
|
||||
crop10: '无固定期限',
|
||||
crop11: '已通过',
|
||||
crop12: '暂无',
|
||||
crop13: '2025-01-01',
|
||||
},
|
||||
{
|
||||
crop1: '100003',
|
||||
crop2: '耿马原生茶叶种植专业合作社',
|
||||
crop3: '蔬菜',
|
||||
crop4: '>20人',
|
||||
crop5: '云南省临沧市耿马县四排山公路20公里处',
|
||||
crop6: '李伟荣',
|
||||
crop7: '13529623147',
|
||||
crop8: '935309260752901376',
|
||||
crop9: '图片',
|
||||
crop10: '无固定期限',
|
||||
crop11: '已通过',
|
||||
crop12: '暂无',
|
||||
crop13: '2025-02-11',
|
||||
},
|
||||
{
|
||||
crop1: '100004',
|
||||
crop2: '耿马华侨金果源农业专业合作社',
|
||||
crop3: '蔬菜',
|
||||
crop4: '>20人',
|
||||
crop5: '云南省临沧市耿马县华侨管理区第五居民小组',
|
||||
crop6: '严共洪',
|
||||
crop7: '13987011022',
|
||||
crop8: '93530926MA6L3A7F8T',
|
||||
crop9: '图片',
|
||||
crop10: '无固定期限',
|
||||
crop11: '已通过',
|
||||
crop12: '暂无',
|
||||
crop13: '2025-03-01',
|
||||
},
|
||||
{
|
||||
crop1: '100005',
|
||||
crop2: '耿马尖山沿边魔芋种植农民专业合作社',
|
||||
crop3: '蔬菜',
|
||||
crop4: '>20人',
|
||||
crop5: '云南省临沧市耿马傣族佤族自治县孟定镇尖山村沿线9公里处',
|
||||
crop6: '商德伟',
|
||||
crop7: '13888526321',
|
||||
crop8: '93530926MA6KR6E41C',
|
||||
crop9: '图片',
|
||||
crop10: '无固定期限',
|
||||
crop11: '已通过',
|
||||
crop12: '暂无',
|
||||
crop13: '2025-04-25',
|
||||
},
|
||||
]);
|
||||
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
query: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
},
|
||||
form: {},
|
||||
selection: [],
|
||||
options: {
|
||||
...CRUD_OPTIONS,
|
||||
addBtnText: '添加',
|
||||
searchLabelWidth: '120px',
|
||||
searchSpan: 8,
|
||||
searchGutter: 100,
|
||||
searchMenuPosition: 'center',
|
||||
column: [
|
||||
{
|
||||
label: '主体代码',
|
||||
prop: 'crop1',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
search: true,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '主体名称',
|
||||
prop: 'crop2',
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '经营产品种类',
|
||||
prop: 'crop3',
|
||||
type: 'select',
|
||||
remote: false,
|
||||
search: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
props: {
|
||||
label: 'landName',
|
||||
value: 'id',
|
||||
},
|
||||
dicHeaders: {
|
||||
authorization: UserStore.token,
|
||||
},
|
||||
dicUrl: `${VITE_APP_BASE_API}/land-resource/landManage/page?current=1&size=9999&draftsSaveType=0&landName=&gridName=&owner=`,
|
||||
dicFormatter: (res) => res.data.records ?? [],
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请选择地块',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
change: handleLandChange,
|
||||
},
|
||||
// {
|
||||
// label: '主要经营产品',
|
||||
// showOverflowTooltip: true,
|
||||
// search: false,
|
||||
// addDisplay: false,
|
||||
// editDisplay: false,
|
||||
// rules: {
|
||||
// required: true,
|
||||
// message: '请输入',
|
||||
// trigger: 'blur',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
label: '合作社规模',
|
||||
prop: 'crop4',
|
||||
search: false,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// label: '网格区域',
|
||||
// prop: 'cities',
|
||||
// type: 'cascader',
|
||||
// hide: true,
|
||||
// addDisplay: true,
|
||||
// editDisplay: true,
|
||||
// viewDisplay: false,
|
||||
// // multiple: true,
|
||||
// // checkStrictly: true,
|
||||
// // collapseTags: true,
|
||||
// // emitPath: false,
|
||||
// // checkDescendants: 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',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
label: '合作社地址',
|
||||
prop: 'crop5',
|
||||
type: 'cascader',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
checkStrictly: false,
|
||||
search: 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',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '负责人',
|
||||
prop: 'crop6',
|
||||
search: false,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '负责人电话',
|
||||
prop: 'crop7',
|
||||
search: false,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '企业信用代码',
|
||||
prop: 'crop8',
|
||||
search: false,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// label: '经营许可证',
|
||||
// prop: 'crop9',
|
||||
// search: false,
|
||||
// addDisplay: false,
|
||||
// editDisplay: false,
|
||||
// rules: {
|
||||
// required: true,
|
||||
// message: '请输入',
|
||||
// trigger: 'blur',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
label: '经营有效期',
|
||||
prop: 'crop10',
|
||||
search: false,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '审核状态',
|
||||
prop: 'crop11',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
search: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '审核意见',
|
||||
prop: 'crop12',
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
rules: {
|
||||
required: true,
|
||||
message: '请输入',
|
||||
trigger: 'blur',
|
||||
},
|
||||
},
|
||||
{ label: '创建时间', prop: 'crop13', addDisplay: false, editDisplay: false, search: false },
|
||||
],
|
||||
group: [
|
||||
{
|
||||
label: '基本信息>',
|
||||
prop: 'caseInfo',
|
||||
column: [
|
||||
{
|
||||
label: '主体名称',
|
||||
prop: 'businessName',
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '合作社类型',
|
||||
prop: 'bType',
|
||||
type: 'select',
|
||||
dicData: bTypeOptions,
|
||||
rules: { required: true, message: '请选择', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '经营产品种类',
|
||||
type: 'select',
|
||||
dicData: productTypeOptions,
|
||||
rules: { required: true, message: '请选择', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '主要产品',
|
||||
prop: 'primaryProduct',
|
||||
rules: { required: false, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '合作社规模',
|
||||
prop: 'inspectionType',
|
||||
rules: { required: false, message: '请选择', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '负责人',
|
||||
prop: 'inspectionTarget',
|
||||
rules: { required: false, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '负责人电话',
|
||||
prop: 'inspectionTarget',
|
||||
rules: { required: false, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '合作社地址',
|
||||
prop: 'villageCode',
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
type: 'cascader',
|
||||
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 ?? [],
|
||||
},
|
||||
{
|
||||
label: '详细地址',
|
||||
prop: 'notes',
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '营业执照>',
|
||||
prop: 'caseInfo',
|
||||
column: [
|
||||
{
|
||||
label: '统一社会信用代码',
|
||||
prop: 'notes',
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '营业执照',
|
||||
prop: 'license',
|
||||
},
|
||||
{
|
||||
label: '有效期至',
|
||||
prop: 'operationDate',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: 200,
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '经营项目',
|
||||
prop: 'inspectionSituation',
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '经营许可证>',
|
||||
prop: 'caseInfo',
|
||||
column: [
|
||||
{
|
||||
label: '经营许可证编号',
|
||||
prop: 'operationType',
|
||||
rules: { required: false, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '经营许可证',
|
||||
prop: 'permit',
|
||||
rules: { required: false, message: '请选择', trigger: 'blur' },
|
||||
},
|
||||
{
|
||||
label: '有效期至',
|
||||
prop: 'operationDate',
|
||||
type: 'date',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: 200,
|
||||
rules: { required: true, message: '请输入', trigger: 'blur' },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
searchColumn: [
|
||||
{ label: '主体代码', prop: 'landName', search: true },
|
||||
{ label: '主体名称', prop: 'crop', search: true },
|
||||
{
|
||||
label: '经营产品种类',
|
||||
prop: 'operationType',
|
||||
type: 'select',
|
||||
search: true,
|
||||
dicData: productTypeOptions,
|
||||
},
|
||||
{
|
||||
label: '创建日期',
|
||||
prop: 'operationDate',
|
||||
type: 'daterange',
|
||||
format: 'YYYY-MM-DD',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
width: 200,
|
||||
search: true,
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
name: '详情',
|
||||
icon: 'View',
|
||||
event: ({ row }) => doDetail(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 loadData = () => {
|
||||
// state.loading = true;
|
||||
// getOperationRecord(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 handleIds = () => {
|
||||
let datalist = state.selection.map((m) => {
|
||||
return { landId: m.landId, landName: m.landName };
|
||||
});
|
||||
|
||||
let selectIdlist = uniqueObjects(datalist, 'landId');
|
||||
let selectIdsVal = selectIdlist.map((n) => {
|
||||
return n.landId;
|
||||
});
|
||||
|
||||
return selectIdsVal.toString() || '';
|
||||
};
|
||||
|
||||
function uniqueObjects(arr, key) {
|
||||
return arr.reduce((acc, current) => {
|
||||
const duplicate = acc.find((element) => element[key] === current[key]);
|
||||
if (!duplicate) {
|
||||
acc.push(current);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
// 新增
|
||||
const rowSave = (row, done, loading) => {
|
||||
// console.info('新增', row);
|
||||
saveOperationRecord(row)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
app.$message.success('添加成功!');
|
||||
done();
|
||||
loadData();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
app.$message.error(err.msg);
|
||||
})
|
||||
.finally(() => {
|
||||
loading();
|
||||
});
|
||||
};
|
||||
|
||||
// 编辑
|
||||
const rowEdit = (row) => {
|
||||
console.info('编辑', row);
|
||||
crudRef.value.rowEdit(row);
|
||||
};
|
||||
|
||||
const doDetail = (row) => {
|
||||
crudRef.value.rowView(row);
|
||||
};
|
||||
const rowUpdate = (row, index, done, loading) => {
|
||||
console.info('更新');
|
||||
editOperationRecord(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(() => {
|
||||
console.info('删除', row.recordId);
|
||||
delOperationRecord(row.recordId || '')
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
app.$message.success('删除成功!');
|
||||
loadData();
|
||||
done();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
app.$message.error(err.msg);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
const onBatchDel = () => {
|
||||
let ids = handleIds();
|
||||
if (!ids.length || ids.length <= 0) {
|
||||
return app.$message.error('请先选择要删除的数据');
|
||||
}
|
||||
};
|
||||
|
||||
const fileChange = (name, list) => {
|
||||
console.info('父组件', list);
|
||||
};
|
||||
</script>
|
@ -13,7 +13,7 @@
|
||||
|
||||
<!-- 四个固定 Tabs -->
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabChange">
|
||||
<el-tab-pane label="待提交" name="0" />
|
||||
<!-- <el-tab-pane label="待提交" name="0" /> -->
|
||||
<el-tab-pane label="待审核" name="1" />
|
||||
<el-tab-pane label="已通过" name="2" />
|
||||
<el-tab-pane label="已驳回" name="3" />
|
||||
@ -141,7 +141,7 @@ const isAuditor = computed(() => role.value === 'auditor');
|
||||
// ---------------------------------------------------------------------
|
||||
// 2. Tab 与数据的状态控制
|
||||
// ---------------------------------------------------------------------
|
||||
const activeTab = ref('0');
|
||||
const activeTab = ref('1');
|
||||
const dialogTitle = ref('新增');
|
||||
const isReadonly = ref(false);
|
||||
// 搜索表单模型
|
||||
@ -203,26 +203,19 @@ const crudOptions = reactive({
|
||||
emptyBtn: false,
|
||||
refreshBtn: false,
|
||||
column: [
|
||||
{ label: '生产经营主体编码', prop: 'id' },
|
||||
{ label: '姓名', prop: 'name' },
|
||||
{
|
||||
label: '证件类型',
|
||||
prop: 'idType',
|
||||
formatter: (row, column, cellValue) => {
|
||||
return cellValue === '101' ? '身份证' : cellValue === '2' ? '护照' : cellValue === '3' ? '港澳身份证' : '';
|
||||
},
|
||||
},
|
||||
{ label: '证件号码', prop: 'idCardEncrypt' },
|
||||
{
|
||||
label: '性别',
|
||||
prop: 'sex',
|
||||
formatter: (row, column, cellValue) => {
|
||||
return cellValue === '1' ? '男' : cellValue === '0' ? '女' : '';
|
||||
},
|
||||
},
|
||||
{ label: '年龄', prop: 'age' },
|
||||
{ label: '联系方式', prop: 'phone' },
|
||||
{ label: '居住地行政区划', prop: 'address' },
|
||||
// 地址
|
||||
{ label: '地址', prop: 'address', width: '300px' },
|
||||
{ label: '地块数量', prop: 'villageCount' },
|
||||
{ label: '地块编号', prop: 'villageCode' },
|
||||
{ label: '地块名称', prop: 'villageName' },
|
||||
{ label: '面积', prop: 'area', formatter: (row, column, cellValue) => `${Number(cellValue).toFixed(2)} 亩` },
|
||||
{ label: '所属行政区划', prop: 'address' },
|
||||
{ label: '所属网格', prop: 'gridCode' },
|
||||
{ label: '种植作物', prop: 'planCropName' },
|
||||
{ label: '账号(手机号)', prop: 'account' },
|
||||
{ label: '创建时间', prop: 'createTime' },
|
||||
{ label: '更新时间', prop: 'updateTime' },
|
||||
],
|
||||
|
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<LandCrud type="forest" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import LandCrud from './components/LandCrud.vue';
|
||||
</script>
|
@ -142,18 +142,8 @@
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="visible = false">取消</el-button>
|
||||
|
||||
<!-- 土地基本信息 tab -->
|
||||
<template v-if="activeFormTab === 'basic'">
|
||||
<el-button type="primary" @click="submitBasicInfo">暂存</el-button>
|
||||
<el-button @click="activeFormTab = 'property'">下一步</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 土地产权信息 tab -->
|
||||
<template v-else>
|
||||
<el-button @click="activeFormTab = 'basic'">上一步</el-button>
|
||||
<el-button v-if="formData.id" type="primary" @click="submitPropertyInfo">提交</el-button>
|
||||
<el-button v-else type="primary" @click="submitAll">保存</el-button>
|
||||
<template v-if="!isReadonly">
|
||||
<el-button type="primary" @click="submitAll">修改</el-button>
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
@ -272,6 +262,22 @@ const crudOptions = reactive({
|
||||
icon: 'delete',
|
||||
event: ({ row }) => handleDelete(row),
|
||||
},
|
||||
{
|
||||
name: '审核',
|
||||
icon: 'approve',
|
||||
event: ({ row }) => onApprove(row),
|
||||
},
|
||||
// TODO: 驳回应该有填写驳回原因的弹窗
|
||||
{
|
||||
name: '驳回',
|
||||
icon: 'reject',
|
||||
event: ({ row }) => onReject(row),
|
||||
},
|
||||
{
|
||||
name: '驳回原因',
|
||||
icon: 'reject',
|
||||
event: ({ row }) => onRejectReason(row),
|
||||
},
|
||||
],
|
||||
});
|
||||
const handleTabChange = ({ name }) => {
|
||||
@ -347,7 +353,7 @@ const handleSubmit = async () => {
|
||||
// ---------------------------------------------------------------------
|
||||
// 业务代码
|
||||
// ---------------------------------------------------------------------
|
||||
import { createLand, deleteLand, editLand, fetchLandList, getLandById } from '@/apis/landResourceManagement/landManagement';
|
||||
import { createLand, deleteLand, editLand, fetchLandList, getLandById, approveLand } from '@/apis/landResourceManagement/landManagement';
|
||||
|
||||
onMounted(() => {
|
||||
getData();
|
||||
@ -385,6 +391,53 @@ const fetchLandTypeData = async () => {
|
||||
console.error('获取土地类型数据失败', error);
|
||||
}
|
||||
};
|
||||
const submitAll = async () => {
|
||||
console.log('提交表单:', formData.value);
|
||||
await editLand(formData.value);
|
||||
ElMessage.success('保存成功');
|
||||
resetForm();
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const onApprove = async (row) => {
|
||||
// UNSUBMIT(-1,"未提交"),
|
||||
// REVIEW(0,"待审核"),
|
||||
// PASS(1,"通过"),
|
||||
// REFUSE(2,"驳回");
|
||||
if (row.landStatus !== 0) {
|
||||
ElMessage.error('该地块状态不是待审核状态');
|
||||
return;
|
||||
}
|
||||
const requiredBody = {
|
||||
bizType: 'landResInfo',
|
||||
bizId: row.id,
|
||||
status: 1,
|
||||
opinion: '',
|
||||
};
|
||||
await approveLand(requiredBody);
|
||||
ElMessage.success('审核成功');
|
||||
getData();
|
||||
};
|
||||
|
||||
const onReject = async (row) => {
|
||||
if (row.landStatus !== 0) {
|
||||
ElMessage.error('该地块状态不是待审核状态');
|
||||
return;
|
||||
}
|
||||
const requiredBody = {
|
||||
bizType: 'landResInfo',
|
||||
bizId: row.id,
|
||||
status: 2,
|
||||
opinion: '',
|
||||
};
|
||||
await approveLand(requiredBody);
|
||||
ElMessage.success('驳回成功');
|
||||
getData();
|
||||
};
|
||||
// 显示驳回原因
|
||||
const onRejectReason = async (row) => {
|
||||
ElMessageBox.alert(row.rejectReason || '无驳回原因', '驳回原因');
|
||||
};
|
||||
const handleAdd = () => {
|
||||
console.log('handleAdd');
|
||||
resetForm();
|
||||
|
@ -1,20 +1,401 @@
|
||||
<template>
|
||||
<div class="custom-page" :style="`background-image: url(${getAssetsFile('images/landBase/land1.png')})`">
|
||||
<!-- <h1>统计数据</h1>
|
||||
<div class="content"></div> -->
|
||||
<div class="field-management">
|
||||
<!-- 左侧面板 -->
|
||||
<div class="panel left">
|
||||
<el-input v-model="searchTerm" placeholder="搜索地块名称" clearable style="margin-bottom: 15px"></el-input>
|
||||
|
||||
<el-table :data="filteredFields" highlight-current-row style="width: 100%" height="calc(100vh - 300px)" @row-click="selectField">
|
||||
<el-table-column prop="name" label="名称"></el-table-column>
|
||||
<el-table-column prop="area" label="面积(㎡)">
|
||||
<template #default="{ row }">
|
||||
{{ row.area.toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="stats">总面积: {{ totalArea.toFixed(2) }} ㎡</div>
|
||||
|
||||
<div class="button-group">
|
||||
<el-button type="primary" @click="startDrawing">新增地块</el-button>
|
||||
<el-button type="danger" :disabled="!selectedField" @click="removeField">删除地块</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧地图区域 -->
|
||||
<div class="panel right">
|
||||
<tdt-map class="map" :center="mapCenter" :zoom="mapZoom" @init="onMapInit"> </tdt-map>
|
||||
|
||||
<div class="layer-switch">
|
||||
<el-radio-group v-model="layerType" size="small" @change="changeBaseLayer">
|
||||
<el-radio-button label="vector">矢量</el-radio-button>
|
||||
<el-radio-button label="image">影像</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div class="field-layer-switch">
|
||||
<el-switch v-model="showFieldLayer" active-text="显示地块"></el-switch>
|
||||
</div>
|
||||
|
||||
<div class="zoom-scale">缩放级别: {{ mapZoom }}, 比例尺: 1:{{ scale.toLocaleString() }}</div>
|
||||
|
||||
<el-dialog v-model="drawDialogVisible" title="新增地块">
|
||||
<el-form>
|
||||
<el-form-item label="地块名称">
|
||||
<el-input v-model="newFieldName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="地块面积">
|
||||
<el-input :value="newFieldArea.toFixed(2) + ' ㎡'" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="cancelDrawing">取消</el-button>
|
||||
<el-button type="primary" @click="saveNewField">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, computed } from 'vue';
|
||||
import { getAssetsFile } from '@/utils';
|
||||
import { ref, computed, onMounted, watch } from 'vue';
|
||||
import { TdtMap } from 'vue-tianditu';
|
||||
import { ElMessage } from 'element-plus';
|
||||
// import { map_config } from '../../config/map';
|
||||
|
||||
// 模拟接口服务(使用localStorage)
|
||||
const fieldService = {
|
||||
getFields() {
|
||||
const fields = localStorage.getItem('fields');
|
||||
return Promise.resolve(fields ? JSON.parse(fields) : []);
|
||||
},
|
||||
createField(field) {
|
||||
return this.getFields().then((fields) => {
|
||||
field.id = Date.now();
|
||||
fields.push(field);
|
||||
localStorage.setItem('fields', JSON.stringify(fields));
|
||||
return field;
|
||||
});
|
||||
},
|
||||
deleteField(id) {
|
||||
return this.getFields().then((fields) => {
|
||||
const newFields = fields.filter((f) => f.id !== id);
|
||||
localStorage.setItem('fields', JSON.stringify(newFields));
|
||||
return newFields;
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// 响应式状态
|
||||
const fields = ref([]);
|
||||
const selectedField = ref(null);
|
||||
const searchTerm = ref('');
|
||||
const newFieldName = ref('');
|
||||
const drawDialogVisible = ref(false);
|
||||
const newFieldCoords = ref([]);
|
||||
const newFieldArea = ref(0);
|
||||
const layerType = ref('vector');
|
||||
const showFieldLayer = ref(true);
|
||||
const map = ref(null);
|
||||
const mapCenter = ref([100.088, 23.883]);
|
||||
const mapZoom = ref(12);
|
||||
const scale = ref(0);
|
||||
|
||||
// 天地图图层
|
||||
const baseLayers = {
|
||||
vector: null,
|
||||
vectorLabel: null,
|
||||
image: null,
|
||||
imageLabel: null,
|
||||
};
|
||||
|
||||
// 覆盖物图层
|
||||
const overlayLayer = ref(null);
|
||||
|
||||
// 计算属性
|
||||
const filteredFields = computed(() => {
|
||||
const term = searchTerm.value.toLowerCase();
|
||||
return term ? fields.value.filter((f) => f.name.toLowerCase().includes(term)) : fields.value;
|
||||
});
|
||||
|
||||
const totalArea = computed(() => {
|
||||
return fields.value.reduce((sum, field) => sum + field.area, 0);
|
||||
});
|
||||
|
||||
// 地图初始化
|
||||
const onMapInit = (mapInstance) => {
|
||||
map.value = mapInstance;
|
||||
|
||||
// 创建图层
|
||||
baseLayers.vector = new T.TileLayer('vec');
|
||||
baseLayers.vectorLabel = new T.TileLayer('cva');
|
||||
baseLayers.image = new T.TileLayer('img');
|
||||
baseLayers.imageLabel = new T.TileLayer('cia');
|
||||
|
||||
// 添加默认图层
|
||||
map.value.addLayer(baseLayers.image);
|
||||
map.value.addLayer(baseLayers.imageLabel);
|
||||
|
||||
// 创建覆盖物图层
|
||||
overlayLayer.value = new T.Map.OverlayLayer();
|
||||
map.value.addLayer(overlayLayer.value);
|
||||
|
||||
// 添加控件
|
||||
map.value.addControl(new T.Control.Zoom());
|
||||
map.value.addControl(new T.Control.Scale());
|
||||
|
||||
// 事件监听
|
||||
map.value.addEventListener('zoomend', updateScale);
|
||||
map.value.addEventListener('moveend', updateScale);
|
||||
|
||||
// 初始加载数据
|
||||
loadFields();
|
||||
};
|
||||
|
||||
// 更新比例尺
|
||||
const updateScale = () => {
|
||||
if (map.value) {
|
||||
mapZoom.value = map.value.getZoom();
|
||||
scale.value = Math.round(map.value.getScale());
|
||||
}
|
||||
};
|
||||
|
||||
// 切换底图
|
||||
const changeBaseLayer = () => {
|
||||
if (!map.value) return;
|
||||
|
||||
// 移除当前底图
|
||||
map.value.removeLayer(baseLayers.vector);
|
||||
map.value.removeLayer(baseLayers.vectorLabel);
|
||||
map.value.removeLayer(baseLayers.image);
|
||||
map.value.removeLayer(baseLayers.imageLabel);
|
||||
|
||||
// 添加新底图
|
||||
if (layerType.value === 'vector') {
|
||||
map.value.addLayer(baseLayers.vector);
|
||||
map.value.addLayer(baseLayers.vectorLabel);
|
||||
} else {
|
||||
map.value.addLayer(baseLayers.image);
|
||||
map.value.addLayer(baseLayers.imageLabel);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载地块数据
|
||||
const loadFields = () => {
|
||||
fieldService.getFields().then((data) => {
|
||||
fields.value = data;
|
||||
refreshOverlays();
|
||||
});
|
||||
};
|
||||
|
||||
// 刷新覆盖物
|
||||
const refreshOverlays = () => {
|
||||
if (!map.value || !overlayLayer.value) return;
|
||||
|
||||
// 清除所有覆盖物
|
||||
overlayLayer.value.clearOverLays();
|
||||
|
||||
// 如果不显示地块图层则跳过绘制
|
||||
if (!showFieldLayer.value) return;
|
||||
|
||||
// 绘制所有地块
|
||||
fields.value.forEach((field) => {
|
||||
const isSelected = selectedField.value?.id === field.id;
|
||||
const polygon = createPolygon(field, isSelected);
|
||||
overlayLayer.value.addOverLay(polygon);
|
||||
});
|
||||
};
|
||||
|
||||
// 创建多边形
|
||||
const createPolygon = (field, isSelected = false) => {
|
||||
const coords = field.geometry.coordinates[0].map((c) => new T.LngLat(c[0], c[1]));
|
||||
return new T.Polygon(coords, {
|
||||
color: isSelected ? '#ff0000' : '#1890ff',
|
||||
weight: isSelected ? 3 : 2,
|
||||
opacity: 0.8,
|
||||
fillColor: isSelected ? '#ffa39e' : '#e6f7ff',
|
||||
fillOpacity: 0.5,
|
||||
});
|
||||
};
|
||||
|
||||
// 选择地块
|
||||
const selectField = (field) => {
|
||||
selectedField.value = field;
|
||||
refreshOverlays();
|
||||
|
||||
// 居中显示选中地块
|
||||
if (map.value) {
|
||||
const coords = field.geometry.coordinates[0];
|
||||
const center = coords.reduce(
|
||||
(acc, coord) => {
|
||||
acc[0] += coord[0];
|
||||
acc[1] += coord[1];
|
||||
return acc;
|
||||
},
|
||||
[0, 0]
|
||||
);
|
||||
|
||||
center[0] /= coords.length;
|
||||
center[1] /= coords.length;
|
||||
|
||||
map.value.panTo(new T.LngLat(center[0], center[1]));
|
||||
}
|
||||
};
|
||||
|
||||
// 开始绘制
|
||||
const startDrawing = () => {
|
||||
if (!map.value) return;
|
||||
|
||||
// 清除当前覆盖物
|
||||
refreshOverlays();
|
||||
|
||||
// 创建绘制工具
|
||||
const polygonTool = new T.PolygonTool(map.value, {
|
||||
showLabel: true,
|
||||
color: '#fa541c',
|
||||
weight: 3,
|
||||
opacity: 0.6,
|
||||
fillColor: '#ffbb96',
|
||||
fillOpacity: 0.4,
|
||||
});
|
||||
|
||||
polygonTool.open();
|
||||
|
||||
// 绘制完成事件
|
||||
polygonTool.addEventListener('draw', (e) => {
|
||||
newFieldCoords.value = e.currentLnglats.map((lnglat) => [lnglat.lng, lnglat.lat]);
|
||||
newFieldArea.value = e.currentArea;
|
||||
drawDialogVisible.value = true;
|
||||
|
||||
// 清除临时图形
|
||||
polygonTool.close();
|
||||
});
|
||||
};
|
||||
|
||||
// 保存新地块
|
||||
const saveNewField = () => {
|
||||
if (!newFieldName.value.trim()) {
|
||||
ElMessage.error('请输入地块名称');
|
||||
return;
|
||||
}
|
||||
|
||||
const newField = {
|
||||
id: Date.now(),
|
||||
name: newFieldName.value,
|
||||
area: newFieldArea.value,
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [newFieldCoords.value],
|
||||
},
|
||||
};
|
||||
|
||||
fieldService.createField(newField).then(() => {
|
||||
ElMessage.success('地块创建成功');
|
||||
drawDialogVisible.value = false;
|
||||
newFieldName.value = '';
|
||||
loadFields();
|
||||
});
|
||||
};
|
||||
|
||||
// 取消绘制
|
||||
const cancelDrawing = () => {
|
||||
drawDialogVisible.value = false;
|
||||
refreshOverlays();
|
||||
};
|
||||
|
||||
// 删除地块
|
||||
const removeField = () => {
|
||||
if (!selectedField.value) return;
|
||||
|
||||
fieldService.deleteField(selectedField.value.id).then(() => {
|
||||
ElMessage.success('地块已删除');
|
||||
selectedField.value = null;
|
||||
loadFields();
|
||||
});
|
||||
};
|
||||
|
||||
// 监听地块图层显示状态
|
||||
watch(showFieldLayer, refreshOverlays);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-page {
|
||||
height: calc(100vh - 150px);
|
||||
background-size: cover;
|
||||
// background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
<style scoped>
|
||||
.field-management {
|
||||
display: flex;
|
||||
height: calc(100vh - 160px);
|
||||
}
|
||||
|
||||
.panel.left {
|
||||
width: 320px;
|
||||
padding: 15px;
|
||||
border-right: 1px solid #e4e7ed;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.panel.right {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.layer-switch {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
background: white;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.field-layer-switch {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
right: 15px;
|
||||
background: white;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.zoom-scale {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.stats {
|
||||
padding: 12px;
|
||||
margin: 10px 0;
|
||||
background: #edf2ff;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
color: #364fc7;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.button-group > * {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div class="mapDiv">
|
||||
<tdt-map ref="tdtMapRef" :center="state.center" :zoom="state.zoom" :style="{ height: mapHeight }">
|
||||
<!-- <tdt-tile-layer :layer-type="'img_w'"></tdt-tile-layer> -->
|
||||
<!-- <tdt-tile-layer :layer-type="'cia_w'" :z-index="2"></tdt-tile-layer> -->
|
||||
<tdt-tilelayer :url="state.img_w_url" :z-index="1"></tdt-tilelayer>
|
||||
<tdt-tilelayer :url="state.cia_w_url" :z-index="2"></tdt-tilelayer>
|
||||
</tdt-map>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { TdtMap, TdtTileLayer } from 'vue-tianditu';
|
||||
import { map_config } from '@/config/map';
|
||||
|
||||
const key = map_config.tianditu.token;
|
||||
|
||||
const state = reactive({
|
||||
center: [100.088, 23.883],
|
||||
zoom: 14,
|
||||
img_w_url: `http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${key}`,
|
||||
cia_w_url: `http://t0.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${key}`,
|
||||
// 添加其他地图层URL
|
||||
// ...
|
||||
});
|
||||
|
||||
// 确保地图有明确的高度
|
||||
const mapHeight = ref('100vh');
|
||||
|
||||
onMounted(() => {
|
||||
console.log('地图组件已挂载');
|
||||
// 检查天地图API是否加载成功
|
||||
if (window.T) {
|
||||
console.log('天地图API已加载:', window.T);
|
||||
} else {
|
||||
console.error('天地图API未加载');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mapDiv {
|
||||
width: 100%;
|
||||
height: 100vh; /* 确保容器有明确高度 */
|
||||
}
|
||||
</style>
|
@ -1,13 +1,130 @@
|
||||
<template>
|
||||
<div class="custom-page" :style="`background-image: url(${getAssetsFile('images/landBase/land2.png')})`">
|
||||
<!-- <h1>统计数据</h1>
|
||||
<div class="content"></div> -->
|
||||
<!-- <div class="custom-page" :style="`background-image: url(${getAssetsFile('images/landBase/land2.png')})`"> -->
|
||||
<div class="custom-page">
|
||||
<!-- <h1>统计数据</h1> -->
|
||||
<div class="content">
|
||||
<div style="display: flex">
|
||||
<pieChart v-for="(item, index) in data" :key="index" class="m-left" :refs="item.refs" :title="item.title" :data="item.data" />
|
||||
</div>
|
||||
<div style="display: flex; margin-top: 20px">
|
||||
<pieChart v-for="(item, index) in data1" :key="index" class="m-left" :refs="item.refs" :title="item.title" :data="item.data" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted, computed } from 'vue';
|
||||
import { getAssetsFile } from '@/utils';
|
||||
import { getOverview, getSubArea } from '../../../apis/resource/statisticAnalysis';
|
||||
import { ref, onBeforeMount, reactive } from 'vue';
|
||||
import 'echarts-gl';
|
||||
import pieChart from './components/pie-chart.vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
let dataColor0 = ['#01D3D3', '#00C4F2', '#4A68FF', '#00DD97', '#01D3D3', '#00C4F2', '#4A68FF', '#00DD97'];
|
||||
let data = ref([
|
||||
{
|
||||
title: '农用地面积数据',
|
||||
data: [],
|
||||
refs: 'chart1',
|
||||
},
|
||||
{
|
||||
title: '土地流转面积数据',
|
||||
data: [],
|
||||
refs: 'chart1',
|
||||
},
|
||||
{
|
||||
title: '耕地面积数据',
|
||||
data: [],
|
||||
refs: 'chart1',
|
||||
},
|
||||
]);
|
||||
|
||||
let data1 = ref([
|
||||
{
|
||||
title: '园地面积数据',
|
||||
data: [],
|
||||
refs: 'chart1',
|
||||
},
|
||||
{
|
||||
title: '林地面积数据',
|
||||
data: [],
|
||||
refs: 'chart1',
|
||||
},
|
||||
{
|
||||
title: '草地面积数据',
|
||||
data: [],
|
||||
refs: 'chart1',
|
||||
},
|
||||
]);
|
||||
|
||||
onBeforeMount(() => {
|
||||
getData();
|
||||
});
|
||||
|
||||
const getData = async () => {
|
||||
try {
|
||||
let res = await getOverview();
|
||||
console.log(res);
|
||||
let res1 = await getOverview({ landTransfer: 1 });
|
||||
res1.data.list.forEach((data2, index) => {
|
||||
data.value[1].data.push({
|
||||
name: data2.landTypeName,
|
||||
value: data2.area,
|
||||
itemStyle: {
|
||||
opacity: 0.9,
|
||||
color: dataColor0[index],
|
||||
},
|
||||
});
|
||||
});
|
||||
res.data.list.forEach(async (data1, index) => {
|
||||
data.value[0].data.push({
|
||||
name: data1.landTypeName,
|
||||
value: data1.area,
|
||||
itemStyle: {
|
||||
opacity: 0.9,
|
||||
color: dataColor0[index],
|
||||
},
|
||||
});
|
||||
// data.value[0].data[index].value = data1.area;
|
||||
// data.value[0].data[index].name = data1.landTypeName;
|
||||
getOrderData({ pid: data1.landTypeId, landTransfer: 1 }, index);
|
||||
});
|
||||
|
||||
console.log(data.value);
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message || '新增失败,请重试');
|
||||
}
|
||||
};
|
||||
|
||||
const getOrderData = async (datas, indexs) => {
|
||||
let res = await getSubArea(datas);
|
||||
if (res.data.title) {
|
||||
if (res.data.title == '耕地面积数据') {
|
||||
res.data.data.forEach((data3, index) => {
|
||||
data.value[2].data.push({
|
||||
name: data3.landTypeName,
|
||||
value: data3.area,
|
||||
itemStyle: {
|
||||
opacity: 0.9,
|
||||
color: dataColor0[index],
|
||||
},
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.data.data.forEach((data4, index) => {
|
||||
console.log(indexs);
|
||||
|
||||
data1.value[indexs - 1].data.push({
|
||||
name: data4.landTypeName,
|
||||
value: data4.area,
|
||||
itemStyle: {
|
||||
opacity: 0.9,
|
||||
color: dataColor0[index],
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@ -16,4 +133,7 @@ import { getAssetsFile } from '@/utils';
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.m-left {
|
||||
margin-left: 2%;
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<el-dialog :v-model="visible" :title="dialogTitle" width="600px" destroy-on-close :close-on-click-modal="false">
|
||||
<el-form ref="formRef" :model="formModel" :rules="rules" :disabled="isView" label-width="100px">
|
||||
<el-form-item label="地块名称" prop="name">
|
||||
<el-input v-model="formModel.name" placeholder="请输入地块名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属区域" prop="areaCode">
|
||||
<AreaSelect v-model="formModel.areaCode" :emit-path="false" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="面积(亩)" prop="area">
|
||||
<el-input-number v-model="formModel.area" :min="0" placeholder="请输入面积" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="图像文件" prop="image">
|
||||
<FileUploader v-model="formModel.image" :limit="1" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formModel.remark" type="textarea" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="close">取消</el-button>
|
||||
<el-button v-if="!isView" type="primary" :loading="submitting" @click="submit">保存</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
initialData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'create', // 'create' | 'edit' | 'view'
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '', // 地块类型:grass / forest / field
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:visible', 'submit']);
|
||||
|
||||
const formRef = ref(null);
|
||||
const formModel = ref({});
|
||||
const submitting = ref(false);
|
||||
|
||||
const isView = computed(() => props.mode === 'view');
|
||||
const dialogTitle = computed(() => {
|
||||
switch (props.mode) {
|
||||
case 'create':
|
||||
return '新增地块';
|
||||
case 'edit':
|
||||
return '编辑地块';
|
||||
case 'view':
|
||||
return '查看地块';
|
||||
default:
|
||||
return '地块信息';
|
||||
}
|
||||
});
|
||||
|
||||
const rules = {
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
areaCode: [{ required: true, message: '请选择区域', trigger: 'change' }],
|
||||
area: [{ required: true, message: '请输入面积', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (val) {
|
||||
formModel.value = { ...props.initialData };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function close() {
|
||||
emit('update:visible', false);
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!formRef.value) return;
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
submitting.value = true;
|
||||
emit('submit', { ...formModel.value });
|
||||
} catch (err) {
|
||||
console.warn('表单校验失败', err);
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="land-search">
|
||||
<el-form :model="search" inline label-width="100px">
|
||||
<el-form-item label="地块名称">
|
||||
<el-input v-model="search.name" placeholder="请输入地块名称" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属区域">
|
||||
<AreaCascader v-model:region-code="search.regionCode" v-model:grid-id="search.id" :width="300" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSearch">搜索</el-button>
|
||||
<el-button @click="onReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch, toRefs } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
search: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:search', 'search', 'reset']);
|
||||
|
||||
const search = reactive({ ...props.search });
|
||||
|
||||
watch(
|
||||
search,
|
||||
(val) => {
|
||||
emit('update:search', { ...val });
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const onSearch = () => {
|
||||
emit('search');
|
||||
};
|
||||
|
||||
const onReset = () => {
|
||||
Object.keys(search).forEach((key) => {
|
||||
search[key] = '';
|
||||
});
|
||||
emit('update:search', { ...search });
|
||||
emit('reset');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.land-search {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<!-- <div class="custom-page" :style="`background-image: url(${getAssetsFile('images/landBase/land2.png')})`"> -->
|
||||
<div>
|
||||
<!-- <h1>统计数据</h1> -->
|
||||
<div class="content">
|
||||
<div :ref="props.refs" style="width: 500px; height: 350px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, reactive, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import 'echarts-gl';
|
||||
import { defineProps } from 'vue';
|
||||
import { size } from 'lodash';
|
||||
// 定义props
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return '暂无';
|
||||
},
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
refs: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return '';
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let chart1 = ref(null);
|
||||
|
||||
console.log(props.refs);
|
||||
|
||||
let option = ref({});
|
||||
|
||||
watch(props.data, (data, oldata) => {
|
||||
console.log(data);
|
||||
let instance = echarts.init(chart1.value);
|
||||
instance.setOption(option.value);
|
||||
});
|
||||
|
||||
option.value = {
|
||||
title: {
|
||||
text: props.title,
|
||||
x: 'center',
|
||||
size: 10,
|
||||
},
|
||||
// backgroundColor: '#0f375f',
|
||||
legend: {
|
||||
top: 25,
|
||||
left: '0',
|
||||
itemWidth: 20,
|
||||
itemHeight: 15,
|
||||
textStyle: {
|
||||
color: '#aab2cd',
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b} <br/>面积: {c}万亩 ({d}%)',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b}: {c}万亩',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: '70%',
|
||||
center: ['40%', '60%'],
|
||||
label: {
|
||||
normal: {
|
||||
fontSize: 16,
|
||||
},
|
||||
},
|
||||
data: props.data,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let instance = echarts.init(chart1.value);
|
||||
instance.setOption(option.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-page {
|
||||
height: calc(100vh - 150px);
|
||||
}
|
||||
.m-left {
|
||||
margin-left: 6%;
|
||||
}
|
||||
</style>
|
@ -1601,6 +1601,11 @@ class-utils@^0.3.5:
|
||||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
claygl@^1.2.1:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmmirror.com/claygl/-/claygl-1.3.0.tgz#7a6e2903210519ac358848f5d78070ed211685f3"
|
||||
integrity sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ==
|
||||
|
||||
clone-regexp@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmmirror.com/clone-regexp/-/clone-regexp-1.0.1.tgz#051805cd33173375d82118fc0918606da39fd60f"
|
||||
@ -2086,6 +2091,14 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1:
|
||||
es-errors "^1.3.0"
|
||||
gopd "^1.2.0"
|
||||
|
||||
echarts-gl@^2.0.9:
|
||||
version "2.0.9"
|
||||
resolved "https://registry.npmmirror.com/echarts-gl/-/echarts-gl-2.0.9.tgz#ee228a6c7520a6fb7bbb71ea94394f3637ade033"
|
||||
integrity sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==
|
||||
dependencies:
|
||||
claygl "^1.2.1"
|
||||
zrender "^5.1.1"
|
||||
|
||||
echarts@^5.6.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.npmmirror.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6"
|
||||
@ -4170,6 +4183,11 @@ minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
|
||||
resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
|
||||
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
|
||||
|
||||
mitt@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1"
|
||||
integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
@ -6503,6 +6521,11 @@ vue-demi@*, vue-demi@^0.14.10:
|
||||
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz#afc78de3d6f9e11bf78c55e8510ee12814522f04"
|
||||
integrity sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==
|
||||
|
||||
vue-demi@^0.12.1:
|
||||
version "0.12.5"
|
||||
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.12.5.tgz#8eeed566a7d86eb090209a11723f887d28aeb2d1"
|
||||
integrity sha512-BREuTgTYlUr0zw0EZn3hnhC3I6gPWv+Kwh4MCih6QcAeaTlaIX0DwOVN0wHej7hSvDPecz4jygy/idsgKfW58Q==
|
||||
|
||||
vue-eslint-parser@^9.4.3:
|
||||
version "9.4.3"
|
||||
resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz#9b04b22c71401f1e8bca9be7c3e3416a4bde76a8"
|
||||
@ -6523,6 +6546,14 @@ vue-router@^4.2.5:
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.6.4"
|
||||
|
||||
vue-tianditu@^2.7.6:
|
||||
version "2.7.6"
|
||||
resolved "https://registry.npmmirror.com/vue-tianditu/-/vue-tianditu-2.7.6.tgz#c48425c49306300cae9664182dd170c626a38371"
|
||||
integrity sha512-Yvcxg0IAgGB3ZY8zlC5ayjo9f85fa8PFTaifguTNpri76g67GO9toaRWMjBKi39yYHMBADaT3P6bEkJx87X8MQ==
|
||||
dependencies:
|
||||
mitt "^3.0.0"
|
||||
vue-demi "^0.12.1"
|
||||
|
||||
vue@^3.3.11:
|
||||
version "3.5.13"
|
||||
resolved "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz#9f760a1a982b09c0c04a867903fc339c9f29ec0a"
|
||||
@ -6679,7 +6710,7 @@ yocto-queue@^0.1.0:
|
||||
resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
zrender@5.6.1:
|
||||
zrender@5.6.1, zrender@^5.1.1:
|
||||
version "5.6.1"
|
||||
resolved "https://registry.npmmirror.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b"
|
||||
integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==
|
||||
|
Loading…
x
Reference in New Issue
Block a user