Compare commits

..

No commits in common. "6a87415fee042ca8b631f5b7a3925164d301c4a3" and "b48ed6b5cb1f11346fbe785db7fa6c6d0f04c174" have entirely different histories.

4 changed files with 366 additions and 179 deletions

View File

@ -18,13 +18,6 @@ export function getLandList(params) {
params, params,
}); });
} }
// 新增全部土地信息POST
export function createLand(data = {}) {
return request('/land-resource/landManage/v1/save', {
method: 'POST',
data,
});
}
/** /**
* 保存土地基础信息 * 保存土地基础信息

View File

@ -120,8 +120,6 @@ const containerStyle = computed(() => ({
text-align: right; text-align: right;
line-height: 32px; line-height: 32px;
width: 120px; width: 120px;
box-sizing: border-box;
padding-right: 12px;
} }
.controls { .controls {
display: flex; display: flex;

View File

@ -30,96 +30,154 @@
</avue-crud> </avue-crud>
<!-- 新增弹窗 --> <!-- 新增弹窗 -->
<el-dialog :key="dialogTitle" v-model="visible" :title="dialogTitle" width="60%" align-center :draggable="true"> <el-dialog v-model="addDialogVisible" title="新增" width="800px" top="8vh">
<el-tabs v-model="activeTab" class="tabs-wrapper"> <el-tabs v-model="activeTab">
<el-tab-pane label="土地基本信息" name="basic"> <el-tab-pane label="土地基本信息" name="basic">
<p class="form-title">编辑基本信息</p> <el-form ref="basicFormRef" :model="formDataBasic" :rules="basicRules" label-width="120px" class="form-container">
<el-form ref="basicFormRef" :model="formDataBasic" :disabled="isReadonly" label-width="120px"> <el-form-item label="地块名称" prop="landName">
<el-row :gutter="20"> <el-input v-model="formDataBasic.landName" placeholder="请输入地块名称" />
<el-col :span="12"> </el-form-item>
<el-form-item label="地块名称" prop="landName"> <el-form-item label="面积(亩)" prop="area">
<el-input v-model="formDataBasic.landName" placeholder="请输入地块名称" /> <el-input-number v-model="formDataBasic.area" :min="0" :precision="2" :step="0.1" controls-position="right" style="width: 100%" />
</el-form-item> </el-form-item>
<el-form-item label="土地类型" prop="landType"> <el-form-item label="土地类型" prop="landType">
<el-select v-model="formDataBasic.landType" placeholder="选择土地类型" clearable> <el-select v-model="formDataBasic.landType" placeholder="选择土地类型" clearable>
<el-option v-for="item in landTypeOptions" :key="item.id" :label="item.landType" :value="item.id" /> <el-option v-for="item in landTypeOptions" :key="item.id" :label="item.landType" :value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="具体位置" prop="address"> <el-form-item label="具体位置" prop="address">
<el-input v-model="formDataBasic.address" placeholder="请输入具体位置" /> <el-input v-model="formDataBasic.address" placeholder="请输入具体位置" />
</el-form-item> </el-form-item>
<el-form-item label="土壤类型" prop="soilTypeId"> <el-form-item label="所属网格" prop="gridId">
<url-select <AreaCascader v-model:region-code="formDataBasic.regionCode" v-model:grid-id="formDataBasic.gridId" label="" :width="500" />
v-model="formDataBasic.soilTypeId" </el-form-item>
placeholder="选择土壤类型" <el-form-item label="土壤类型" prop="soilTypeId">
url="/land-resource/baseInfo/soilTypePage" <url-select
:params="{ current: 1, size: 100 }" v-model="formDataBasic.soilTypeId"
label-key="soilType" placeholder="选择土壤类型"
value-key="id" url="/land-resource/baseInfo/soilTypePage"
:clearable="true" :params="{ current: 1, size: 100 }"
/> label-key="soilType"
</el-form-item> value-key="id"
<el-form-item label="土地照片" prop="landUrl"> :clearable="true"
<FileUploader v-model="formDataBasic.landUrl" :limit="1" /> />
</el-form-item> </el-form-item>
</el-col> <el-form-item label="土地照片" prop="landUrl">
<el-col :span="12"> <el-upload
<el-form-item label="面积(亩)" prop="area"> :http-request="customUploadRequest"
<el-input-number v-model="formDataBasic.area" :min="0" :precision="2" :step="0.1" controls-position="right" style="width: 100%" /> :on-success="(res, file) => handleUploadSuccess(res, file, 'basic')"
</el-form-item> multiple
:show-file-list="true"
<el-form-item label="" label-width="0" prop="gridId"> >
<AreaCascader v-model:region-code="formDataBasic.regionCode" v-model:grid-id="formDataBasic.gridId" label="" :split-rows="true" /> <template #trigger>
</el-form-item> <el-button type="primary">点击上传</el-button>
</template>
<el-form-item label="土地范围" prop="scope"> </el-upload>
<el-input v-model="formDataBasic.scope" placeholder="请输入土地范围" /> </el-form-item>
<!-- <Attrs v-model:attrs="formDataBasic.scope" type="add" accept="image/*" /> --> <el-form-item label="土地范围" prop="scope">
</el-form-item> <el-input v-model="formDataBasic.scope" placeholder="请输入土地范围" />
</el-col> <!-- <Attrs v-model:attrs="formDataBasic.scope" type="add" accept="image/*" /> -->
</el-row> </el-form-item>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="土地产权信息" name="property"> <el-tab-pane label="土地产权信息" name="property">
<p class="form-title">编辑产权信息</p> <el-form ref="propertyFormRef" :model="formDataProperty" :rules="propertyRules" label-width="120px" class="form-container">
<el-form ref="propertyFormRef" style="width: 60%" :model="formDataProperty" :disabled="isReadonly" label-width="120px"> <el-form-item label="地块名称">
<el-row :gutter="20"> <el-input v-model="formDataProperty.landName" disabled />
<el-form-item label="地块名称"> </el-form-item>
<el-input v-model="formDataProperty.landName" disabled /> <el-form-item label="产权人姓名" prop="propertyName">
</el-form-item> <el-input v-model="formDataProperty.propertyName" placeholder="请输入产权人姓名" />
<el-form-item label="产权人姓名" prop="propertyName"> </el-form-item>
<el-input v-model="formDataProperty.propertyName" placeholder="请输入产权人姓名" /> <el-form-item label="联系方式" prop="propertyPhone">
</el-form-item> <el-input v-model="formDataProperty.propertyPhone" placeholder="请输入产权人联系方式" />
<el-form-item label="联系方式" prop="propertyPhone"> </el-form-item>
<el-input v-model="formDataProperty.propertyPhone" placeholder="请输入产权人联系方式" /> <el-form-item label="产权编号" prop="landCode">
</el-form-item> <el-input v-model="formDataProperty.landCode" placeholder="请输入产权编号" />
<el-form-item label="产权编号" prop="landCode"> </el-form-item>
<el-input v-model="formDataProperty.landCode" placeholder="请输入产权编号" /> <el-form-item label="产权证书" prop="propertyCertificateUrl">
</el-form-item> <FileUploader v-model="formDataProperty.propertyCertificateUrl" :limit="1" />
<el-form-item label="产权证书" prop="propertyCertificateUrl"> </el-form-item>
<FileUploader v-model="formDataProperty.propertyCertificateUrl" :limit="1" />
</el-form-item>
</el-row>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="visible = false">取消</el-button> <el-button @click="addDialogVisible = false">取消</el-button>
<el-button v-if="activeTab === 'basic'" type="primary" @click="handleAddSubmit('basic')">提交</el-button>
<el-button v-if="activeTab === 'basic'" :disabled="disabledProperty" @click="activeTab = 'property'">下一步</el-button>
<el-button v-else @click="activeTab = 'basic'">上一步</el-button>
<el-button v-if="activeTab === 'property'" type="primary" @click="handleAddSubmit('property')"> 提交 </el-button>
</span>
</template>
</el-dialog>
<!-- 土地基本信息 tab --> <!-- 查看和编辑共用弹窗 -->
<template v-if="activeTab === 'basic'"> <el-dialog v-model="viewEditDialogVisible" :title="viewEditTitle" width="800px" top="8vh">
<el-button type="primary" @click="submitBasicInfo">暂存</el-button> <el-form
<el-button @click="activeTab = 'property'">下一步</el-button> ref="viewEditFormRef"
</template> :model="viewEditFormData"
:rules="isView ? {} : editRules"
label-width="120px"
class="view-edit-form"
:disabled="isView"
>
<h3 class="section-title">土地基本信息</h3>
<el-form-item label="地块名称" prop="landName">
<el-input v-model="viewEditFormData.landName" />
</el-form-item>
<el-form-item label="面积(亩)" prop="area">
<el-input-number v-model="viewEditFormData.area" :min="0" :precision="2" :step="0.1" controls-position="right" style="width: 100%" />
</el-form-item>
<el-form-item label="土地类型" prop="landType">
<el-select v-model="viewEditFormData.landType" clearable>
<el-option v-for="item in landTypeOptions" :key="item.id" :label="item.landType" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="具体位置" prop="address">
<el-input v-model="viewEditFormData.address" />
</el-form-item>
<el-form-item label="所属网格" prop="gridId">
<AreaCascader v-model="viewEditFormData.regionCode" v-model:grid-id="viewEditFormData.gridId" :width="500" label="" />
</el-form-item>
<el-form-item label="土壤类型" prop="soilTypeId">
<url-select
v-model="viewEditFormData.soilTypeId"
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="viewEditFormData.landUrl" :limit="1" />
</el-form-item>
<el-form-item label="土地范围" prop="scope">
<el-input v-model="viewEditFormData.scope" />
</el-form-item>
<!-- 土地产权信息 tab --> <h3 class="section-title">土地产权信息</h3>
<template v-else> <el-form-item label="产权人姓名" prop="propertyName">
<el-button @click="activeTab = 'basic'">上一步</el-button> <el-input v-model="viewEditFormData.propertyName" />
<el-button v-if="formDataProperty.landId" type="primary" @click="submitPropertyInfo">提交</el-button> </el-form-item>
<el-button v-else type="primary" @click="submitAll">保存</el-button> <el-form-item label="联系方式" prop="propertyPhone">
</template> <el-input v-model="viewEditFormData.propertyPhone" />
</el-form-item>
<el-form-item label="产权编号" prop="landCode">
<el-input v-model="viewEditFormData.landCode" />
</el-form-item>
<el-form-item label="产权证书" prop="propertyCertificateUrl">
<FileUploader v-model="viewEditFormData.propertyCertificateUrl" :limit="1" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="viewEditDialogVisible = false">{{ isView ? '关闭' : '取消' }}</el-button>
<el-button v-if="isView" type="primary" @click="handleEdit">编辑</el-button>
<el-button v-if="!isView" type="primary" @click="handleView">查看</el-button>
<el-button v-if="!isView" type="primary" @click="handleViewEditSubmit"> 提交 </el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -129,9 +187,8 @@
<script setup> <script setup>
import { ref, reactive, onMounted, computed, nextTick } from 'vue'; import { ref, reactive, onMounted, computed, nextTick } from 'vue';
import { CRUD_OPTIONS } from '@/config'; import { CRUD_OPTIONS } from '@/config';
import { getLandList, createLand, saveBaseInfo, saveProperty, editLand, deleteLand } from '@/apis/landResourceManagement/landManagement'; import { getLandList, saveBaseInfo, saveProperty, editLand, deleteLand } from '@/apis/landResourceManagement/landManagement';
import { CommonUpload } from '@/apis/index'; import { CommonUpload } from '@/apis/index';
import { ElMessage, ElMessageBox } from 'element-plus';
import request from '@/utils/axios'; import request from '@/utils/axios';
// ============================== // ==============================
@ -139,14 +196,17 @@ import request from '@/utils/axios';
// ============================== // ==============================
const loading = ref(false); const loading = ref(false);
const crudRef = ref(); const crudRef = ref();
const visible = ref(false); const addDialogVisible = ref(false);
const isReadonly = ref(false);
const activeTab = ref('basic'); const activeTab = ref('basic');
const dialogTitle = ref('新增'); const viewEditDialogVisible = ref(false);
const isView = ref(false);
//
const isValidationEnabled = ref(false);
// //
const basicFormRef = ref(null); const basicFormRef = ref(null);
const propertyFormRef = ref(null); const propertyFormRef = ref(null);
const viewEditFormRef = ref(null);
// //
const pageData = ref({ const pageData = ref({
@ -191,6 +251,97 @@ const formDataProperty = ref({
propertyCertificateUrl: '', propertyCertificateUrl: '',
}); });
const viewEditFormData = ref({
id: '',
landName: '',
gridId: '',
gridName: '',
area: 0,
landType: '',
landTypeId: '',
landTypeName: '',
address: '',
detailAddress: '',
fullLandType: '',
fullRegionName: '',
soilTypeId: '',
soilType: '',
landUrl: '',
scope: '',
propertyName: '',
propertyPhone: '',
landCode: '',
propertyCertificateUrl: '',
updateTime: '',
});
// OSS URL
const ossUrl = 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/';
// ==============================
//
// ==============================
const viewEditTitle = computed(() => {
return isView.value ? '查看' : '编辑';
});
const disabledProperty = computed(() => {
return formDataBasic.value.id ? false : true;
});
// ==============================
//
// ==============================
const basicRules = reactive(
isValidationEnabled.value
? {
landName: [{ required: true, message: '请输入地块名称', trigger: 'blur' }],
area: [
{ required: true, message: '请输入面积', trigger: 'blur' },
{
type: 'number',
min: 0,
message: '面积必须大于0',
trigger: 'blur',
},
],
landType: [{ required: true, message: '请选择土地类型', trigger: 'change' }],
address: [{ required: true, message: '请输入具体位置', trigger: 'blur' }],
gridId: [{ required: true, message: '请选择所属网格', trigger: 'change' }],
soilTypeId: [{ required: true, message: '请选择土壤类型', trigger: 'change' }],
landUrl: [{ required: true, message: '请上传土地照片', trigger: 'change' }],
scope: [{ required: true, message: '请输入土地范围', trigger: 'blur' }],
}
: {}
);
const propertyRules = reactive(
isValidationEnabled.value
? {
propertyName: [{ required: true, message: '请输入产权人姓名', trigger: 'blur' }],
propertyPhone: [
{ required: true, message: '请输入联系方式', trigger: 'blur' },
{
pattern: /^1[3-9]\d{9}$/,
message: '请输入正确的手机号码',
trigger: 'blur',
},
],
landCode: [{ required: true, message: '请输入产权编号', trigger: 'blur' }],
propertyCertificateUrl: [{ required: true, message: '请上传产权证书', trigger: 'change' }],
}
: {}
);
const editRules = reactive(
isValidationEnabled.value
? {
...basicRules,
...propertyRules,
}
: {}
);
// ============================== // ==============================
// CRUD // CRUD
// ============================== // ==============================
@ -202,7 +353,7 @@ const option = reactive({
column: [ column: [
{ label: '地块名称', prop: 'landName' }, { label: '地块名称', prop: 'landName' },
{ label: '所属网格', prop: 'gridName' }, { label: '所属网格', prop: 'gridName' },
{ label: '面积', prop: 'area', formatter: (row, column, cellValue) => `${Number(cellValue).toFixed(2)}` }, { label: '面积', prop: 'area', formatter: (row, column, cellValue) => `${cellValue}` },
{ label: '土地类型', prop: 'landTypeName' }, { label: '土地类型', prop: 'landTypeName' },
{ label: '所属行政区域', prop: 'fullRegionName' }, { label: '所属行政区域', prop: 'fullRegionName' },
{ label: '具体位置', prop: 'address' }, { label: '具体位置', prop: 'address' },
@ -213,16 +364,16 @@ const option = reactive({
{ label: '信息更新时间', prop: 'updateTime' }, { label: '信息更新时间', prop: 'updateTime' },
], ],
actions: [ actions: [
// { {
// name: '', name: '查看',
// icon: 'view', icon: 'view',
// event: ({ row }) => handleView(row), event: ({ row }) => handleView(row),
// }, },
// { {
// name: '', name: '编辑',
// icon: 'edit', icon: 'edit',
// event: ({ row }) => handleEdit(row), event: ({ row }) => handleEdit(row),
// }, },
{ {
type: 'danger', type: 'danger',
name: '删除', name: '删除',
@ -289,7 +440,7 @@ const handleAdd = () => {
propertyCertificateUrl: '', propertyCertificateUrl: '',
}; };
visible.value = true; addDialogVisible.value = true;
activeTab.value = 'basic'; activeTab.value = 'basic';
// //
@ -304,15 +455,22 @@ const handleAdd = () => {
}; };
const handleView = (row) => { const handleView = (row) => {
isReadonly.value = true; isView.value = true;
dialogTitle.value = '土地资源详情'; viewEditFormData.value = { ...row };
visible.value = true; viewEditDialogVisible.value = true;
}; };
const handleEdit = (row) => { const handleEdit = (row) => {
dialogTitle.value = '编辑'; isView.value = false;
isReadonly.value = false; viewEditFormData.value = { ...row };
visible.value = true; viewEditDialogVisible.value = true;
//
// nextTick(() => {
// if (viewEditFormRef.value) {
// viewEditFormRef.value.resetFields();
// }
// });
}; };
const handleDelete = (id) => { const handleDelete = (id) => {
@ -342,57 +500,94 @@ const resetSearch = () => {
// ============================== // ==============================
// - // -
// ============================== // ==============================
const submitBasicInfo = async () => { const handleAddSubmit = async (tab) => {
try { try {
await basicFormRef.value.validate(); if (tab === 'basic') {
const res = await saveBaseInfo(formDataBasic.value); await basicFormRef.value.validate();
if (res.code === 200) { const res = await saveBaseInfo(formDataBasic.value);
formDataProperty.value.id = res.data.id; if (res.code === 200) {
formDataProperty.value.landName = formDataBasic.value.landName; activeTab.value = 'property';
ElMessage.success('基本信息已暂存'); formDataProperty.value.id = res.data.id;
formDataProperty.value.landName = formDataBasic.value.landName;
}
} else if (tab === 'property') {
await propertyFormRef.value.validate();
const res = await saveProperty(formDataProperty.value);
if (res.code === 200) {
addDialogVisible.value = false;
getData();
}
} }
} catch (error) { } catch (error) {
console.error('暂存失败', error); console.error('表单提交失败', error);
} }
}; };
const submitPropertyInfo = async () => { const handleViewEditSubmit = async () => {
try { try {
await propertyFormRef.value.validate(); await viewEditFormRef.value.validate();
if (!formDataProperty.value.id) { //
ElMessage.error('请先保存基本信息'); const { id, ...formData } = viewEditFormData.value;
return; if (id) {
} //
const res = await saveProperty(formDataProperty.value); // await updateLandInfo({ id, ...formData });
if (res.code === 200) { await editLand({ id, ...formData });
ElMessage.success('产权信息提交成功'); viewEditDialogVisible.value = false;
visible.value = false;
getData(); getData();
} }
} catch (error) { } catch (error) {
console.error('产权信息提交失败', error); console.error('表单提交失败', error);
} }
}; };
const submitAll = async () => { // ==============================
try { // -
await basicFormRef.value.validate(); // ==============================
await propertyFormRef.value.validate(); const customUploadRequest = async (options) => {
const formData = new FormData();
formData.append('file', options.file);
const combinedData = { try {
...formDataProperty.value, const response = await CommonUpload(formData);
...formDataBasic.value, options.onSuccess(response, options.file);
}; return response;
const baseRes = await createLand(combinedData); } catch (err) {
if (baseRes.code === 200) { console.error('上传失败', err);
ElMessage.success('全部信息保存成功'); options.onError(err);
visible.value = false; throw err;
getData(); }
} else { };
ElMessage.error('信息保存失败');
const handleUploadSuccess = (res, file, type) => {
if (res?.data?.url) {
const url = res.data.url;
switch (type) {
case 'basic':
formDataBasic.value.landUrl = url;
break;
case 'property':
formDataProperty.value.propertyCertificateUrl = url;
break;
case 'viewEditBasic':
viewEditFormData.value.landUrl = url;
break;
case 'viewEditProperty':
viewEditFormData.value.propertyCertificateUrl = url;
break;
} }
} catch (error) {
console.error('保存失败', error); //
nextTick(() => {
if (type === 'basic' && basicFormRef.value) {
basicFormRef.value.validateField('landUrl');
} else if (type === 'property' && propertyFormRef.value) {
propertyFormRef.value.validateField('propertyCertificateUrl');
} else if (type.includes('viewEdit') && viewEditFormRef.value) {
const field = type === 'viewEditBasic' ? 'landUrl' : 'propertyCertificateUrl';
viewEditFormRef.value.validateField(field);
}
});
} }
}; };
@ -421,11 +616,6 @@ onMounted(() => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// :deep(.el-dialog__body) {
// padding: 20px;
// height: calc(100vh - 300px);
// overflow-y: auto;
// }
.custom-page { .custom-page {
padding: 20px; padding: 20px;
height: calc(100vh - 150px); height: calc(100vh - 150px);
@ -442,40 +632,40 @@ onMounted(() => {
} }
} }
} }
.tabs-wrapper {
width: 100%;
display: flex;
align-items: center;
// background-color: #7daaaa;
:deep(.el-tabs__item) { .form-container,
font-size: 16px; .view-edit-form {
color: #555555; padding: 0 20px;
font-weight: 500; max-height: calc(100vh - 300px);
// border: 1 solid #f000; overflow-y: auto;
}
:deep(.el-tabs__content) { .el-form-item {
padding: 20px; margin-bottom: 22px;
// background-color: #f5f5f5;
border-radius: 4px;
height: calc(100vh - 300px);
overflow-y: auto;
}
:deep(.el-tab-pane) {
margin: 0 auto;
width: 80%;
} }
} }
.form-title { .view-edit-form {
font-size: 16px; .section-title {
font-weight: 500; color: #409eff;
margin: 30px 0; border-bottom: 1px solid #eee;
color: #333333; padding-bottom: 10px;
margin: 20px 0;
}
.preview-image {
max-width: 100%;
max-height: 200px;
border: 1px solid #eee;
border-radius: 4px;
display: block;
margin-top: 8px;
}
} }
.dialog-footer { .dialog-footer {
display: block; display: flex;
text-align: center; justify-content: flex-end;
padding: 10px 20px 0;
border-top: 1px solid #eee;
} }
</style> </style>

View File

@ -415,4 +415,10 @@ const onExport = () => {
.dialog-footer { .dialog-footer {
text-align: center; text-align: center;
} }
:deep(.area-cascader-label) {
padding: 0 12px 0 0;
margin: 0;
width: 120px;
box-sizing: border-box;
}
</style> </style>