Files
td_official/src/views/project/landTransfer/BusinessLedger/landTransferLedger/index.vue
2025-08-28 23:32:17 +08:00

612 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="p-2 detailbox">
<div class="box1">
<div>
<div>
<span>设计面积</span>
<span>{{ detailInfo.designArea }} </span>
</div>
<el-icon :size="50" color="#3176ff">
<Postcard />
</el-icon>
</div>
<div>
<div>
<span>已流转面积</span>
<span>{{ detailInfo.transferAea }} </span>
</div>
<el-icon :size="50" color="#3176ff">
<Postcard />
</el-icon>
</div>
<div>
<div>
<span>租金</span>
<span>{{ detailInfo.landRent / 1000 }} 万元</span>
</div>
<el-icon :size="50" color="#3176ff">
<Postcard />
</el-icon>
</div>
</div>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="never">
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
<el-form-item label="对应地块" prop="landBlockId">
<el-select v-model="queryParams.landBlockId" clearable placeholder="请选择对应地块">
<el-option v-for="item in landBlockList" :key="item.id" :label="item.landName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="流转台账状态" prop="transferStatus">
<el-select v-model="queryParams.transferStatus" placeholder="请选择流转台账状态" clearable>
<el-option label="待流转" :value="0"></el-option>
<el-option label="已流转" :value="1"></el-option>
</el-select>
</el-form-item>
<el-form-item label="责任人" prop="responsiblePerson">
<el-input v-model="queryParams.responsiblePerson" placeholder="请输入责任人" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landTransferLedger:add']">新增</el-button>
</el-col>
<el-col :span="6"></el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" :data="landTransferLedgerList" @selection-change="handleSelectionChange">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="土地类型" align="center" prop="landTypeName" />
<el-table-column label="地块" align="center" prop="landName" />
<el-table-column label="进场道路" align="center" prop="roadName" />
<el-table-column label="设计面积(亩)" align="center" prop="designArea" width="180" />
<el-table-column label="责任人" align="center" prop="responsiblePerson" />
<el-table-column label="预计完成时间" align="center" prop="expectedFinishDate" width="180"> </el-table-column>
<el-table-column label="流转状态" align="center" prop="transferStatusName" />
<el-table-column label="已流转面积(亩)" align="center" prop="transferAea" width="180" />
<el-table-column label="流转比例(%)" align="center" prop="transferRatio" width="180" />
<el-table-column label="土地租金(元)" align="center" prop="landRent" width="180" />
<el-table-column label="青苗赔偿(元)" align="center" prop="seedlingCompensation" width="180" />
<el-table-column label="总金额(元)" align="center" prop="totalAmount" width="150" />
<el-table-column label="状态说明" align="center" prop="statusDescription" />
<el-table-column label="问题总结" align="center" prop="issueSummary" />
<el-table-column label="下一步策略" align="center" prop="nextStrategy" width="180" />
<el-table-column label="操作" align="center" fixed="right" width="200">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['land:landTransferLedger:edit']">编辑</el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" @click="handleDelete(scope.row)" v-hasPermi="['land:landTransferLedger:remove']">删除</el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改项目土地流转台账对话框 -->
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="900px" append-to-body>
<el-form ref="landTransferLedgerFormRef" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="对应地块" prop="landBlockId">
<el-select v-model="form.landBlockId" clearable placeholder="请选择对应地块" @change="handleLandBlockChange">
<el-option v-for="item in landBlockList" :key="item.id" :label="item.landName" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="进场道路" prop="enterRoadId">
<el-select v-model="form.enterRoadId" clearable placeholder="请选择对应地块">
<el-option v-for="item in enterRoadList" :key="item.id" :label="item.roadName" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="土地类型" prop="landType">
<el-select v-model="form.landType" placeholder="请选择土地类型" clearable>
<el-option v-for="dict in land_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="流转台账状态" prop="transferStatus">
<el-select v-model="form.transferStatus" :disabled="!form.id" placeholder="请选择流转台账状态" clearable @change="calcTransferRatio">
<el-option v-for="dict in land_transfer_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设计面积(亩)" prop="designArea">
<el-input type="number" v-model="form.designArea" placeholder="请输入设计面积" @input="calcTransferRatio" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="责任人" prop="responsiblePerson">
<el-input v-model="form.responsiblePerson" placeholder="请输入责任人" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus != '2'" :span="12">
<el-form-item label="预计完成日期" prop="expectedFinishDate">
<el-date-picker clearable v-model="form.expectedFinishDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择预计完成时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="12">
<el-form-item label="已流转面积(亩)" prop="transferAea">
<el-input v-model="form.transferAea" type="number" placeholder="请输入已流转面积" @input="calcTransferRatio" />
</el-form-item>
</el-col>
<!-- 流转比例改为禁用输入自动计算展示 -->
<el-col v-if="form.transferStatus == '1'" :span="12">
<el-form-item label="流转比例(%)" prop="transferRatio">
<el-input v-model="form.transferRatio" type="text" :disabled="true" placeholder="自动计算中..." />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="12">
<el-form-item label="土地租金(元)" prop="landRent">
<el-input type="number" v-model="form.landRent" placeholder="请输入土地租金" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="12">
<el-form-item label="青苗赔偿(元)" prop="seedlingCompensation">
<el-input v-model="form.seedlingCompensation" type="number" placeholder="请输入青苗赔偿" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="12">
<el-form-item label="总金额(元)" prop="totalAmount">
<el-input type="number" v-model="form.totalAmount" placeholder="请输入总金额" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '2'" :span="12">
<el-form-item label="不签合同面积(亩)" prop="noContractArea">
<el-input v-model="form.noContractArea" type="number" placeholder="请输入不签合同面积" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '2'" :span="12">
<el-form-item label="不测量面积(亩)" prop="noSurveyArea">
<el-input v-model="form.noSurveyArea" type="number" placeholder="请输入不测量面积" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '2'" :span="24">
<el-form-item label="不签合同原因" prop="noContractReason">
<el-input v-model="form.noContractReason" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '2'" :span="24">
<el-form-item label="不流转原因" prop="nonTransferReason">
<el-input v-model="form.nonTransferReason" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="24">
<el-form-item label="状态说明" prop="statusDescription">
<el-input v-model="form.statusDescription" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="24">
<el-form-item label="问题总结" prop="issueSummary">
<el-input v-model="form.issueSummary" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
<el-col v-if="form.transferStatus == '1'" :span="24">
<el-form-item label="下一步策略" prop="nextStrategy">
<el-input v-model="form.nextStrategy" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="LandTransferLedger" lang="ts">
import {
listLandTransferLedger,
getLandTransferLedger,
delLandTransferLedger,
addLandTransferLedger,
updateLandTransferLedger,
landTransferLedgerCount
} from '@/api/system/landTransfer/landTransferLedger';
import { listEnterRoad } from '@/api/system/landTransfer/enterRoad';
import { LandTransferLedgerVO, LandTransferLedgerQuery, LandTransferLedgerForm } from '@/api/system/landTransfer/landTransferLedger/types';
import { useUserStoreHook } from '@/store/modules/user';
import { listLandBlock } from '@/api/system/landTransfer/landBlock';
import { getCurrentInstance, ComponentInternalInstance, watch, onUnmounted, onMounted } from 'vue';
import { ElFormInstance } from 'element-plus';
// 类型定义补充
interface DialogOption {
visible: boolean;
title: string;
}
interface PageData<T, Q> {
form: T;
queryParams: Q;
rules: Record<string, any[]>;
}
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
// 获取用户 store
const userStore = useUserStoreHook();
// 从 store 中获取项目列表和当前选中的项目
const currentProject = computed(() => userStore.selectedProject);
const landTransferLedgerList = ref<LandTransferLedgerVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const landBlockList = ref([]);
const queryFormRef = ref<ElFormInstance>();
const landTransferLedgerFormRef = ref<ElFormInstance>();
const enterRoadList = ref([]);
// 字典数据
const { land_type, land_transfer_status } = toRefs<any>(proxy?.useDict('land_type', 'land_transfer_status'));
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
// 表单初始数据
const initFormData: LandTransferLedgerForm = {
id: undefined,
projectId: currentProject.value?.id,
landType: undefined,
landBlockId: undefined,
enterRoadId: undefined,
designArea: undefined,
responsiblePerson: undefined,
expectedFinishDate: undefined,
transferAea: undefined,
transferRatio: undefined,
landRent: undefined,
seedlingCompensation: undefined,
totalAmount: undefined,
transferStatus: undefined,
statusDescription: undefined,
issueSummary: undefined,
nextStrategy: undefined,
noContractArea: undefined,
noContractReason: undefined,
noSurveyArea: undefined,
nonTransferReason: undefined
};
// 核心数据响应式对象
const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
projectId: currentProject.value?.id,
landType: undefined,
landBlockId: undefined,
enterRoadId: undefined,
designArea: undefined,
responsiblePerson: undefined,
expectedFinishDate: undefined,
transferAea: undefined,
transferRatio: undefined,
landRent: undefined,
seedlingCompensation: undefined,
totalAmount: undefined,
transferStatus: undefined,
statusDescription: undefined,
issueSummary: undefined,
nextStrategy: undefined,
params: {},
listType: 1
},
rules: {
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }],
transferRatio: [
// 动态校验:仅已流转状态下必填
{
required: true,
message: '流转比例不能为空',
trigger: ['blur', 'change'],
validator: (rule, value, callback) => {
if (data.form.transferStatus !== '1') {
callback(); // 非已流转状态跳过校验
return;
}
if (value === undefined || value === null || value === '') {
callback(new Error('流转比例不能为空'));
} else {
callback();
}
}
},
// 比例范围校验0-100
{
validator: (rule, value, callback) => {
if (value < 0 || value > 100) {
callback(new Error('流转比例必须在 0-100 之间'));
} else {
callback();
}
},
trigger: 'blur'
}
]
}
});
const detailInfo = ref({
transferAea: 0,
transferRatio: 0,
landRent: 0
});
const { queryParams, form, rules } = toRefs(data);
/**
* 自动计算流转比例:(已流转面积 / 设计面积) × 100保留2位小数最大100%
*/
const calcTransferRatio = () => {
// 仅已流转状态下计算
if (form.value.transferStatus !== '1') {
form.value.transferRatio = undefined;
return;
}
// 转换为数字(避免字符串计算)
const designArea = Number(form.value.designArea) || 0;
const transferAea = Number(form.value.transferAea) || 0;
// 边界处理设计面积为0时避免报错
if (designArea === 0) {
form.value.transferRatio = 0;
return;
}
// 核心计算限制最大100%保留2位小数
const ratio = Math.min((transferAea / designArea) * 100, 100);
form.value.transferRatio = Number(ratio.toFixed(2));
};
/** 查询项目土地流转台账列表 */
const getList = async () => {
loading.value = true;
try {
const res = await listLandTransferLedger(queryParams.value);
landTransferLedgerList.value = res.rows;
total.value = res.total;
} finally {
loading.value = false;
}
};
/** 获取地块统计信息 */
const getLandBlockList = async () => {
try {
const res = await landTransferLedgerCount(currentProject.value?.id);
detailInfo.value = res.data;
} catch (error) {
console.error('获取地块统计信息失败:', error);
}
};
/** 取消按钮 */
const cancel = () => {
dialog.visible = false;
reset();
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
landTransferLedgerFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: LandTransferLedgerVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length !== 1;
multiple.value = selection.length === 0;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
form.value.transferStatus = '0'; // 默认待流转
enterRoadList.value = [];
dialog.title = '添加项目土地流转台账';
dialog.visible = true;
};
/** 修改按钮操作 */
const handleUpdate = async (row?: LandTransferLedgerVO) => {
reset();
const _id = row?.id || ids.value[0];
if (!_id) return;
try {
// 获取编辑数据
const res = await getLandTransferLedger(_id);
Object.assign(form.value, res.data);
// 回显地块对应的道路列表
form.value.landBlockId = row?.landBlockId;
await getListRoad();
// 初始化计算流转比例
calcTransferRatio();
// 打开弹窗
dialog.title = '修改项目土地流转台账';
dialog.visible = true;
} catch (error) {
console.error('获取编辑数据失败:', error);
proxy?.$modal.msgError('加载数据失败,请重试');
}
};
/** 提交按钮 */
const submitForm = () => {
landTransferLedgerFormRef.value?.validate(async (valid: boolean) => {
if (!valid) return;
buttonLoading.value = true;
try {
if (form.value.id) {
await updateLandTransferLedger(form.value);
} else {
await addLandTransferLedger(form.value);
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
await getLandBlockList(); // 刷新统计信息
} catch (error) {
proxy?.$modal.msgError('操作失败,请重试');
console.error('提交表单失败:', error);
} finally {
buttonLoading.value = false;
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: LandTransferLedgerVO) => {
const _ids = row?.id || ids.value;
if (!_ids.length) return;
try {
await proxy?.$modal.confirm(`是否确认删除项目土地流转台账编号为"${_ids}"的数据项?`);
await delLandTransferLedger(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
await getLandBlockList(); // 刷新统计信息
} catch (error) {
console.error('删除数据失败:', error);
if (error !== 'cancel') {
// 排除用户取消确认的情况
proxy?.$modal.msgError('删除失败,请重试');
}
} finally {
loading.value = false;
}
};
/** 选择地块后加载对应道路 */
const handleLandBlockChange = async () => {
await getListRoad();
};
/** 查询地块列表 */
const getListLand = async () => {
try {
const res = await listLandBlock({
pageNum: 1,
pageSize: 10000,
projectId: currentProject.value?.id
});
landBlockList.value = res.rows;
} catch (error) {
console.error('获取地块列表失败:', error);
}
};
/** 查询进场道路列表(按地块筛选) */
const getListRoad = async () => {
try {
const res = await listEnterRoad({
pageNum: 1,
pageSize: 10000,
projectId: currentProject.value?.id,
landBlockId: form.value.landBlockId
});
enterRoadList.value = res.rows;
} catch (error) {
console.error('获取进场道路列表失败:', error);
}
};
/** 监听项目切换,刷新数据 */
const listeningProject = watch(
() => currentProject.value?.id,
async (newId) => {
if (newId) {
queryParams.value.projectId = newId;
await Promise.all([getLandBlockList(), getListLand(), getList()]);
}
},
{ immediate: true } // 初始加载时触发
);
/** 组件卸载时清理监听 */
onUnmounted(() => {
listeningProject();
});
/** 组件挂载时初始化数据 */
onMounted(() => {
Promise.all([getLandBlockList(), getListLand(), getList()]);
});
</script>
<style lang="scss">
.detailbox {
width: 100%;
.box1 {
width: 100%;
display: flex;
justify-content: center;
margin: 20px 0;
> div {
width: 300px;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 15px;
border: 1px solid #e7e7e7;
margin: 0 20px;
border-radius: 6px;
> div {
display: flex;
flex-direction: column;
> span:first-child {
font-size: 16px;
margin-bottom: 10px;
}
> span:last-child {
font-size: 24px;
/* font-weight: bold; */
}
}
}
}
}
</style>