优化
This commit is contained in:
Binary file not shown.
@ -160,3 +160,13 @@ export const obtainTheVersion = (query: any) => {
|
|||||||
params: query
|
params: query
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* 获取到物资剩余量
|
||||||
|
*/
|
||||||
|
export const mrpBaseRemaining = (query: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/cailiaoshebei/mrpBase/remaining',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -38,7 +38,14 @@
|
|||||||
<el-table-column label="操作" align="center">
|
<el-table-column label="操作" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:extract:query']">审核</el-button>
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['design:extract:query']">审核</el-button>
|
||||||
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['design:extract:export']">导出</el-button
|
<el-button
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
v-if="scope.row.status != 'finish'"
|
||||||
|
icon="Download"
|
||||||
|
@click="handleDownload(scope.row)"
|
||||||
|
v-hasPermi="['design:extract:export']"
|
||||||
|
>导出</el-button
|
||||||
><el-button
|
><el-button
|
||||||
link
|
link
|
||||||
type="warning"
|
type="warning"
|
||||||
@ -65,15 +72,17 @@
|
|||||||
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
|
<el-table :loading="loadingFlie" :data="fileList" style="width: 100%" border>
|
||||||
<el-table-column prop="fileName" label="文件名称" align="center">
|
<el-table-column prop="fileName" label="文件名称" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-link
|
<!-- <el-link
|
||||||
:key="scope.row.fileId"
|
:key="scope.row.fileId"
|
||||||
:href="scope.row.fileUrl"
|
:href="scope.row.fileUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
:type="scope.row.status == '1' ? 'primary' : 'info'"
|
||||||
:underline="false"
|
:underline="false"
|
||||||
|
disabled
|
||||||
>
|
>
|
||||||
{{ scope.row.fileName }}
|
{{ scope.row.fileName }}
|
||||||
</el-link>
|
</el-link> -->
|
||||||
|
<span>{{ scope.row.fileName }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="版本号" align="center" width="120" prop="version"> </el-table-column>
|
<el-table-column label="版本号" align="center" width="120" prop="version"> </el-table-column>
|
||||||
|
@ -445,7 +445,9 @@ const getMajor = async () => {
|
|||||||
let res = await extractUserMajor({ userId: userId.value, projectId: currentProject.value?.id });
|
let res = await extractUserMajor({ userId: userId.value, projectId: currentProject.value?.id });
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
des_user_major.value = res.data;
|
des_user_major.value = res.data;
|
||||||
console.log(des_user_major.value);
|
if (res.data.length > 0) {
|
||||||
|
form.user_major = res.data[0].userMajor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/** 回显表单数据(编辑/查看/审批场景) */
|
/** 回显表单数据(编辑/查看/审批场景) */
|
||||||
|
@ -434,7 +434,7 @@ const onLoad = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.zip`);
|
proxy?.download('design/collect/exportWord', { id: form.id }, `收资清单_${new Date().getTime()}.doc`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('导出失败,请重试');
|
ElMessage.error('导出失败,请重试');
|
||||||
console.error('文件导出错误:', error);
|
console.error('文件导出错误:', error);
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
<el-col :span="1.5" :offset="0"
|
<el-col :span="1.5" :offset="0">
|
||||||
><el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']"
|
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:add']"
|
||||||
size="default"
|
size="default"
|
||||||
@ -15,10 +15,10 @@
|
|||||||
icon="FolderAdd"
|
icon="FolderAdd"
|
||||||
plain
|
plain
|
||||||
>新增</el-button
|
>新增</el-button
|
||||||
></el-col
|
>
|
||||||
>
|
</el-col>
|
||||||
<el-col :span="1.5" :offset="0"
|
<el-col :span="1.5" :offset="0">
|
||||||
><el-button
|
<el-button
|
||||||
type="danger"
|
type="danger"
|
||||||
size="default"
|
size="default"
|
||||||
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']"
|
v-hasPermi="['cailiaoshebei:materialbatchdemandplan:remove']"
|
||||||
@ -27,8 +27,8 @@
|
|||||||
icon="FolderDelete"
|
icon="FolderDelete"
|
||||||
plain
|
plain
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
></el-col
|
>
|
||||||
>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -75,14 +75,11 @@
|
|||||||
>审核</el-button
|
>审核</el-button
|
||||||
>
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="cailiaoshebeiList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="cailiaoshebeiList" @selection-change="handleSelectionChange">
|
||||||
<!-- <el-table-column type="selection" width="55" align="center" /> -->
|
|
||||||
<!-- <el-table-column label="供货商ID" align="center" prop="supplierId" /> -->
|
|
||||||
<el-table-column label="物资名称" align="center" prop="name" />
|
<el-table-column label="物资名称" align="center" prop="name" />
|
||||||
<el-table-column label="质量标准" align="center" prop="qs" />
|
<el-table-column label="质量标准" align="center" prop="qs" />
|
||||||
<el-table-column label="规格型号" align="center" prop="specification" />
|
<el-table-column label="规格型号" align="center" prop="specification" />
|
||||||
@ -103,7 +100,7 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 添加或修改物资-材料设备对话框 -->
|
<!-- 添加或修改物资-材料设备对话框 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="1300px" append-to-body>
|
<el-dialog :close-on-click-modal="false" draggable :title="dialog.title" v-model="dialog.visible" width="1500px" append-to-body>
|
||||||
<el-form :model="form" ref="cailiaoshebeiFormRef" :rules="rules" label-width="80px" :inline="false">
|
<el-form :model="form" ref="cailiaoshebeiFormRef" :rules="rules" label-width="80px" :inline="false">
|
||||||
<el-divider>基础信息</el-divider>
|
<el-divider>基础信息</el-divider>
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
@ -125,63 +122,91 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-divider>主要信息</el-divider>
|
<el-divider>主要信息</el-divider>
|
||||||
<el-table :data="form.planList">
|
<!-- 表格添加border属性,优化视觉体验 -->
|
||||||
<el-table-column prop="name" align="center" label="版本号 " width="150">
|
<el-table :data="form.planList" border>
|
||||||
|
<!-- 版本号列 -->
|
||||||
|
<el-table-column prop="versions" align="center" label="版本号 " width="200">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-select v-model="scope.row.versions" placeholder="请选择" @change="(val) => selectNameVersion(val, scope.row)">
|
<el-select v-model="scope.row.versions" placeholder="请选择" @change="(val) => selectNameVersion(val, scope.row, scope.$index)">
|
||||||
<el-option v-for="item in versionList" :key="item.versions" :label="item.versions" :value="item.versions" />
|
<el-option v-for="item in versionList" :key="item.versions" :label="item.versions" :value="item.versions" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="name" align="center" label="物资名称">
|
<!-- 物资名称列 -->
|
||||||
|
<el-table-column prop="name" align="center" label="物资名称" width="160">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-select
|
<el-select
|
||||||
:disabled="!scope.row.versions"
|
:disabled="!scope.row.versions"
|
||||||
v-model="scope.row.suppliespriceId"
|
v-model="scope.row.suppliespriceId"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
@change="(val) => selectName(val, scope.row)"
|
@change="(val) => selectName(val, scope.row, scope.$index)"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in nameList" :key="item.id" :label="item.name" :value="item.id" />
|
<el-option v-for="item in nameList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="specification" align="center" label="规格型号" width="150">
|
<!-- 剩余量列 -->
|
||||||
|
<el-table-column align="center" label="剩余量" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.specification" placeholder="请输入规格型号" disabled />
|
<span>{{ scope.row.Remaining }}</span>
|
||||||
|
<!-- <el-input disabled v-model="scope.row.Remaining" placeholder="剩余量" /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="unit" align="center" label="单位" width="130">
|
<!-- 规格型号列 -->
|
||||||
|
<el-table-column prop="specification" align="center" label="规格型号" width="100">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.unit" placeholder="请输入单位" disabled />
|
<span>{{ scope.row.specification }}</span>
|
||||||
|
<!-- <el-input v-model="scope.row.specification" placeholder="请输入规格型号" disabled /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="demandQuantity" align="center" label="数量" width="130">
|
<!-- 单位列 -->
|
||||||
|
<el-table-column prop="unit" align="center" label="单位" width="80">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.demandQuantity" placeholder="请输入数量" type="number" min="0" disabled />
|
<span>{{ scope.row.unit }}</span>
|
||||||
|
<!-- <el-input v-model="scope.row.unit" placeholder="请输入单位" disabled /> -->
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="qs" align="center" label="质量标准" width="150">
|
<!-- 数量列(新增错误提示展示) -->
|
||||||
<template #header> <span class="text-red">*</span> 质量标准 </template>
|
<el-table-column prop="demandQuantity" align="center" label="数量" width="140">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input
|
||||||
|
v-model.number="scope.row.demandQuantity"
|
||||||
|
@input="validateDemandQuantity(scope.row, scope.$index)"
|
||||||
|
@blur="validateDemandQuantity(scope.row, scope.$index)"
|
||||||
|
:max="scope.row.Remaining"
|
||||||
|
placeholder="请输入数量"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
<!-- 数量错误提示(红色小字体) -->
|
||||||
|
<div v-if="scope.row.quantityError" class="text-red-500 text-xs mt-1">{{ scope.row.quantityError }}</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- 质量标准列 -->
|
||||||
|
<el-table-column prop="qs" align="center" label="质量标准" width="140">
|
||||||
|
<template #header> <span class="text-red-500">*</span> 质量标准 </template>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.qs" placeholder="请输入质量标准" />
|
<el-input v-model="scope.row.qs" placeholder="请输入质量标准" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="arrivalTime" align="center" label="需求到货时间">
|
<!-- 需求到货时间列 -->
|
||||||
<template #header> <span class="text-red">*</span> 需求到货时间 </template>
|
<el-table-column prop="arrivalTime" align="center" label="需求到货时间" width="180">
|
||||||
|
<template #header> <span class="text-red-500">*</span> 需求到货时间 </template>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-date-picker v-model="scope.row.arrivalTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择" style="width: 140px" />
|
<el-date-picker v-model="scope.row.arrivalTime" type="date" value-format="YYYY-MM-DD" placeholder="请选择" style="width: 140px" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="remark" align="center" label="备注" width="150">
|
<!-- 备注列 -->
|
||||||
|
<el-table-column prop="remark" align="center" label="备注" >
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.remark" placeholder="请输入备注" disabled />
|
<el-input v-model="scope.row.remark" placeholder="请输入备注" disabled />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<!-- 操作列 -->
|
||||||
<el-table-column prop="remark" align="center" label="操作" width="150">
|
<el-table-column prop="remark" align="center" label="操作" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button @click="addRow" type="success" icon="Plus" circle size="small" />
|
<el-button @click="addRow" type="primary" icon="Plus" size="small" />
|
||||||
<el-button @click="delRow(scope.$index)" type="danger" icon="Delete" circle size="small" />
|
<el-button @click="delRow(scope.$index)" type="danger" icon="Delete" size="small" />
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -206,10 +231,47 @@ import {
|
|||||||
listSelectCailiaoshebei,
|
listSelectCailiaoshebei,
|
||||||
obtainTheVersion,
|
obtainTheVersion,
|
||||||
getDictList,
|
getDictList,
|
||||||
coryEngineeringList
|
coryEngineeringList,
|
||||||
|
mrpBaseRemaining
|
||||||
} from '@/api/materials/batchPlan';
|
} from '@/api/materials/batchPlan';
|
||||||
import { CailiaoshebeiVO, CailiaoshebeiQuery, CailiaoshebeiForm } from '@/api/materials/batchPlan/types';
|
import { CailiaoshebeiVO, CailiaoshebeiQuery, CailiaoshebeiForm } from '@/api/materials/batchPlan/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { getCurrentInstance, ComponentInternalInstance, watch, onMounted, onUnmounted } from 'vue';
|
||||||
|
import type { ElFormInstance } from 'element-plus';
|
||||||
|
|
||||||
|
// 类型定义补充
|
||||||
|
interface DialogOption {
|
||||||
|
visible: boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlanListItem {
|
||||||
|
id?: number | undefined;
|
||||||
|
name?: string | undefined;
|
||||||
|
specification?: string | undefined;
|
||||||
|
unit?: string | undefined;
|
||||||
|
suppliespriceId?: number | undefined;
|
||||||
|
demandQuantity?: number | undefined;
|
||||||
|
qs?: string | undefined;
|
||||||
|
arrivalTime?: string | undefined;
|
||||||
|
remark?: string | undefined;
|
||||||
|
Remaining: number; // 剩余量(必存在)
|
||||||
|
quantityError: string; // 数量错误提示
|
||||||
|
versions?: string | undefined; // 版本号
|
||||||
|
duplicateError: string; // 重复错误提示
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
mrpBaseBo: {
|
||||||
|
id?: number | undefined;
|
||||||
|
preparedDate?: string | undefined;
|
||||||
|
planCode?: string | undefined;
|
||||||
|
matCat?: string | undefined;
|
||||||
|
status?: string | undefined;
|
||||||
|
projectId?: number | undefined;
|
||||||
|
};
|
||||||
|
planList: PlanListItem[];
|
||||||
|
}
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
@ -227,17 +289,17 @@ const multiple = ref(true);
|
|||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
const mainTotal = ref(0);
|
const mainTotal = ref(0);
|
||||||
const batchOptions = ref<any[]>([]);
|
const batchOptions = ref<any[]>([]);
|
||||||
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status'));
|
const { wf_business_status } = toRefs<any>(proxy?.useDict('wf_business_status') || {});
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const cailiaoshebeiFormRef = ref<ElFormInstance>();
|
const cailiaoshebeiFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
const initFormData: any = {
|
// 初始化表单数据(补充版本号、重复错误提示字段)
|
||||||
|
const initFormData: FormData = {
|
||||||
mrpBaseBo: {
|
mrpBaseBo: {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
preparedDate: undefined,
|
preparedDate: undefined,
|
||||||
@ -246,7 +308,6 @@ const initFormData: any = {
|
|||||||
status: undefined,
|
status: undefined,
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
},
|
},
|
||||||
|
|
||||||
planList: [
|
planList: [
|
||||||
{
|
{
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@ -257,18 +318,22 @@ const initFormData: any = {
|
|||||||
demandQuantity: undefined,
|
demandQuantity: undefined,
|
||||||
qs: undefined,
|
qs: undefined,
|
||||||
arrivalTime: undefined,
|
arrivalTime: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
|
Remaining: 0, // 初始化剩余量
|
||||||
|
quantityError: '', // 初始化数量错误提示
|
||||||
|
versions: undefined, // 初始化版本号
|
||||||
|
duplicateError: '' // 初始化重复错误提示
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData } as FormData,
|
||||||
queryParams: {
|
queryParams: {
|
||||||
batchData: {
|
batchData: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
planCode: undefined,
|
planCode: undefined,
|
||||||
|
|
||||||
projectId: currentProject.value?.id
|
projectId: currentProject.value?.id
|
||||||
},
|
},
|
||||||
mainData: {
|
mainData: {
|
||||||
@ -285,77 +350,184 @@ const data = reactive({
|
|||||||
'mrpBaseBo.matCat': [{ required: true, message: '物资分类不能为空', trigger: 'blur' }]
|
'mrpBaseBo.matCat': [{ required: true, message: '物资分类不能为空', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const batchNumber = ref('');
|
const batchNumber = ref('');
|
||||||
const { queryParams, form, rules } = toRefs(data);
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
const nameList = ref([]);
|
const nameList = ref<any[]>([]);
|
||||||
const versionList = ref([]);
|
const versionList = ref<any[]>([]);
|
||||||
|
|
||||||
/** 查询物资-材料设备列表 */
|
/** 查询物资-材料设备列表 */
|
||||||
const getList = async (type?: string) => {
|
const getList = async (type?: string) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await listBatch(queryParams.value.batchData);
|
try {
|
||||||
batchOptions.value = res.rows;
|
const res = await listBatch(queryParams.value.batchData);
|
||||||
if (res.rows && res.rows.length > 0 && !queryParams.value.mainData.mrpBaseId) {
|
batchOptions.value = res.rows || [];
|
||||||
batchTreeRef.value.setCurrentKey(res.rows[0].id);
|
// 自动选中第一条数据(如果存在且未选中)
|
||||||
queryParams.value.mainData.mrpBaseId = res.rows[0].id;
|
if (batchOptions.value.length > 0 && !queryParams.value.mainData.mrpBaseId) {
|
||||||
form.value.mrpBaseBo.status = res.rows[0].status;
|
batchTreeRef.value?.setCurrentKey(batchOptions.value[0].id);
|
||||||
|
queryParams.value.mainData.mrpBaseId = batchOptions.value[0].id;
|
||||||
|
form.value.mrpBaseBo.status = batchOptions.value[0].status;
|
||||||
|
}
|
||||||
|
total.value = res.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取批次列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
// 非搜索场景下同步加载主列表
|
||||||
|
if (type !== 'search') {
|
||||||
|
getMainList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
total.value = res.total;
|
|
||||||
loading.value = false;
|
|
||||||
if (type === 'search') return;
|
|
||||||
getMainList();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectName = (val: any, row: any) => {
|
/** 数量校验:必须≤剩余量,且为合法数字 */
|
||||||
const selected = nameList.value.find((item) => item.id === val);
|
const validateDemandQuantity = (row: PlanListItem, index: number) => {
|
||||||
if (selected) {
|
// 1. 清除之前的错误信息
|
||||||
row.name = selected.name;
|
row.quantityError = '';
|
||||||
row.specification = selected.specification;
|
|
||||||
row.unit = selected.unit;
|
// 2. 处理空值(若需必填可补充:row.quantityError = '数量不能为空')
|
||||||
row.qs = selected.qs;
|
if (row.demandQuantity === null || row.demandQuantity === undefined || row.demandQuantity === '') {
|
||||||
row.demandQuantity = selected.quantity;
|
return;
|
||||||
row.remark = selected.remark;
|
|
||||||
row.arrivalTime = selected.arrivalTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 处理非数字
|
||||||
|
if (typeof row.demandQuantity !== 'number' || isNaN(row.demandQuantity)) {
|
||||||
|
row.quantityError = '请输入合法数字';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 处理负数
|
||||||
|
if (row.demandQuantity < 0) {
|
||||||
|
row.quantityError = '数量不能为负数';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 核心校验:数量≤剩余量
|
||||||
|
if (row.demandQuantity > row.Remaining) {
|
||||||
|
row.quantityError = `数量不能超过剩余量${row.Remaining}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 获取剩余量 */
|
||||||
|
const getMrpBaseRemaining = async (suppliespriceId: number, row: PlanListItem) => {
|
||||||
|
try {
|
||||||
|
const res = await mrpBaseRemaining({ suppliespriceId });
|
||||||
|
row.Remaining = res.data || 0;
|
||||||
|
// 剩余量更新后,重新校验当前数量
|
||||||
|
validateDemandQuantity(row, 0);
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取剩余量失败');
|
||||||
|
row.Remaining = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 校验重复数据:版本号+物资名称不能重复 */
|
||||||
|
const checkDuplicate = () => {
|
||||||
|
const planList = form.value.planList;
|
||||||
|
let hasDuplicate = false;
|
||||||
|
|
||||||
|
// 1. 清除所有重复错误提示
|
||||||
|
planList.forEach((item) => {
|
||||||
|
item.duplicateError = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. 遍历校验重复(只校验版本号和物资名称都存在的行)
|
||||||
|
for (let i = 0; i < planList.length; i++) {
|
||||||
|
const current = planList[i];
|
||||||
|
// 跳过版本号或物资名称为空的行
|
||||||
|
if (!current.versions || !current.suppliespriceId) continue;
|
||||||
|
|
||||||
|
for (let j = i + 1; j < planList.length; j++) {
|
||||||
|
const compare = planList[j];
|
||||||
|
if (!compare.versions || !compare.suppliespriceId) continue;
|
||||||
|
|
||||||
|
// 版本号和物资ID都相同则判定为重复
|
||||||
|
if (current.versions === compare.versions && current.suppliespriceId === compare.suppliespriceId) {
|
||||||
|
current.duplicateError = `与第${j + 1}行重复(同版本+同物资)`;
|
||||||
|
compare.duplicateError = `与第${i + 1}行重复(同版本+同物资)`;
|
||||||
|
hasDuplicate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasDuplicate;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选择物资名称触发(新增索引参数,用于触发重复校验) */
|
||||||
|
const selectName = (val: number, row: PlanListItem, index: number) => {
|
||||||
|
// 1. 获取剩余量并更新基础信息
|
||||||
|
getMrpBaseRemaining(val, row).then(() => {
|
||||||
|
const selected = nameList.value.find((item: any) => item.id === val);
|
||||||
|
if (selected) {
|
||||||
|
row.name = selected.name;
|
||||||
|
row.specification = selected.specification;
|
||||||
|
row.unit = selected.unit;
|
||||||
|
row.qs = selected.qs || '';
|
||||||
|
row.remark = selected.remark || '';
|
||||||
|
row.arrivalTime = selected.arrivalTime || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 触发重复校验
|
||||||
|
checkDuplicate();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 节点单击事件 */
|
/** 节点单击事件 */
|
||||||
const handleNodeClick = (data: any) => {
|
const handleNodeClick = (data: any) => {
|
||||||
queryParams.value.mainData.mrpBaseId = data.id;
|
queryParams.value.mainData.mrpBaseId = data.id;
|
||||||
form.value.mrpBaseBo.status = data.status;
|
form.value.mrpBaseBo.status = data.status;
|
||||||
|
|
||||||
getMainList();
|
getMainList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 获取主列表数据 */
|
||||||
const getMainList = async () => {
|
const getMainList = async () => {
|
||||||
if (!queryParams.value.mainData.mrpBaseId) return;
|
if (!queryParams.value.mainData.mrpBaseId) return;
|
||||||
|
|
||||||
const res = await getBatch(queryParams.value.mainData);
|
loading.value = true;
|
||||||
cailiaoshebeiList.value = res.rows;
|
try {
|
||||||
mainTotal.value = res.total;
|
const res = await getBatch(queryParams.value.mainData);
|
||||||
|
cailiaoshebeiList.value = res.rows || [];
|
||||||
|
mainTotal.value = res.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取物资列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 搜索批次列表 */
|
||||||
const searchBatchList = async () => {
|
const searchBatchList = async () => {
|
||||||
queryParams.value.batchData.planCode = batchNumber.value;
|
queryParams.value.batchData.planCode = batchNumber.value;
|
||||||
getList('search');
|
getList('search');
|
||||||
};
|
};
|
||||||
|
|
||||||
//删除
|
/** 删除表格行 */
|
||||||
const delRow = (index: number) => {
|
const delRow = (index: number) => {
|
||||||
if (form.value.planList.length <= 1) return proxy?.$modal.msgWarning('请至少保留一项');
|
if (form.value.planList.length <= 1) {
|
||||||
|
return proxy?.$modal.msgWarning('请至少保留一项物资数据');
|
||||||
|
}
|
||||||
form.value.planList.splice(index, 1);
|
form.value.planList.splice(index, 1);
|
||||||
|
// 删除后重新校验重复(避免删除重复行后错误提示残留)
|
||||||
|
checkDuplicate();
|
||||||
};
|
};
|
||||||
|
|
||||||
//新增
|
/** 新增表格行 */
|
||||||
const addRow = () => {
|
const addRow = () => {
|
||||||
form.value.planList.push({
|
const newRow: PlanListItem = {
|
||||||
name: undefined,
|
name: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
|
suppliespriceId: undefined,
|
||||||
demandQuantity: undefined,
|
demandQuantity: undefined,
|
||||||
qs: undefined,
|
qs: undefined,
|
||||||
arrivalTime: undefined,
|
arrivalTime: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
});
|
Remaining: 0,
|
||||||
|
quantityError: '',
|
||||||
|
versions: undefined,
|
||||||
|
duplicateError: ''
|
||||||
|
};
|
||||||
|
form.value.planList.push(newRow);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -367,41 +539,22 @@ const cancel = () => {
|
|||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
const status = form.value.mrpBaseBo.status;
|
const status = form.value.mrpBaseBo.status;
|
||||||
form.value = { ...initFormData, status }; // 重置但保留
|
// 重置表单(保留状态字段)
|
||||||
|
form.value = {
|
||||||
|
...JSON.parse(JSON.stringify(initFormData)),
|
||||||
|
mrpBaseBo: { ...initFormData.mrpBaseBo, status }
|
||||||
|
};
|
||||||
|
// 重置表单验证状态
|
||||||
cailiaoshebeiFormRef.value?.resetFields();
|
cailiaoshebeiFormRef.value?.resetFields();
|
||||||
|
// 重置项目ID
|
||||||
form.value.mrpBaseBo.projectId = currentProject.value?.id;
|
form.value.mrpBaseBo.projectId = currentProject.value?.id;
|
||||||
form.value.planList = [
|
|
||||||
{
|
|
||||||
name: undefined,
|
|
||||||
specification: undefined,
|
|
||||||
unit: undefined,
|
|
||||||
suppliespriceId: undefined,
|
|
||||||
|
|
||||||
demandQuantity: undefined,
|
|
||||||
qs: undefined,
|
|
||||||
arrivalTime: undefined,
|
|
||||||
remark: undefined
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// /** 搜索按钮操作 */
|
|
||||||
// const handleQuery = () => {
|
|
||||||
// queryParams.value.pageNum = 1;
|
|
||||||
// getList();
|
|
||||||
// };
|
|
||||||
|
|
||||||
// /** 重置按钮操作 */
|
|
||||||
// const resetQuery = () => {
|
|
||||||
// queryFormRef.value?.resetFields();
|
|
||||||
// handleQuery();
|
|
||||||
// };
|
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 多选框选中数据 */
|
||||||
const handleSelectionChange = (selection: CailiaoshebeiVO[]) => {
|
const handleSelectionChange = (selection: CailiaoshebeiVO[]) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length !== 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = selection.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增按钮操作 */
|
||||||
@ -411,93 +564,154 @@ const handleAdd = () => {
|
|||||||
dialog.title = '新增物资-需求';
|
dialog.title = '新增物资-需求';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
const handleUpdata = () => {
|
const handleUpdata = () => {
|
||||||
reset();
|
if (!queryParams.value.mainData.mrpBaseId) {
|
||||||
getCailiaoshebei(queryParams.value.mainData.mrpBaseId).then((res: any) => {
|
return proxy?.$modal.msgError('请先选择批次');
|
||||||
form.value.mrpBaseBo = res.data.mrpBaseBo;
|
|
||||||
const allowedKeys = Object.keys(initFormData.planList[0]);
|
|
||||||
form.value.planList = res.data.planList.map((item) => {
|
|
||||||
return allowedKeys.reduce((obj, key) => {
|
|
||||||
obj[key] = item[key] ?? undefined;
|
|
||||||
return obj;
|
|
||||||
}, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(form.value.planList);
|
|
||||||
});
|
|
||||||
dialog.visible = true;
|
|
||||||
dialog.title = '修改物资-需求';
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 提交数据 */
|
|
||||||
const submitTransferForm = async () => {
|
|
||||||
const result = validateAndClean(form.value.planList);
|
|
||||||
if (!result.valid) {
|
|
||||||
proxy?.$modal.msgError(result.message);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset();
|
||||||
|
loading.value = true;
|
||||||
|
getCailiaoshebei(queryParams.value.mainData.mrpBaseId)
|
||||||
|
.then((res: any) => {
|
||||||
|
// 1. 更新基础信息
|
||||||
|
form.value.mrpBaseBo = res.data.mrpBaseBo || initFormData.mrpBaseBo;
|
||||||
|
// 2. 更新表格数据(补充缺失字段)
|
||||||
|
form.value.planList = (res.data.planList || []).map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name,
|
||||||
|
specification: item.specification,
|
||||||
|
unit: item.unit,
|
||||||
|
suppliespriceId: item.suppliespriceId,
|
||||||
|
demandQuantity: item.demandQuantity,
|
||||||
|
qs: item.qs,
|
||||||
|
arrivalTime: item.arrivalTime,
|
||||||
|
remark: item.remark,
|
||||||
|
Remaining: item.Remaining || 0,
|
||||||
|
quantityError: '',
|
||||||
|
versions: item.versions,
|
||||||
|
duplicateError: ''
|
||||||
|
}));
|
||||||
|
// 3. 打开对话框
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '修改物资-需求';
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
proxy?.$modal.msgError('获取详情失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 提交数据(整合所有校验) */
|
||||||
|
const submitTransferForm = async () => {
|
||||||
|
// 1. 先校验重复数据
|
||||||
|
const hasDuplicate = checkDuplicate();
|
||||||
|
if (hasDuplicate) {
|
||||||
|
return proxy?.$modal.msgError('存在重复的版本号+物资组合,请修正后提交');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 校验数量合法性(检查是否有数量错误)
|
||||||
|
const hasQuantityError = form.value.planList.some((row) => row.quantityError);
|
||||||
|
if (hasQuantityError) {
|
||||||
|
return proxy?.$modal.msgError('存在非法数量,请修正后提交');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 执行表单基础验证
|
||||||
|
const result = validateAndClean(form.value.planList);
|
||||||
|
if (!result.valid) {
|
||||||
|
return proxy?.$modal.msgError(result.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 表单组件验证
|
||||||
cailiaoshebeiFormRef.value?.validate(async (valid: boolean) => {
|
cailiaoshebeiFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
buttonLoading.value = true;
|
|
||||||
form.value.planList = result.data;
|
buttonLoading.value = true;
|
||||||
await updateCailiaoshebei(form.value).finally(() => (buttonLoading.value = false));
|
try {
|
||||||
|
// 5. 提交数据
|
||||||
|
await updateCailiaoshebei({
|
||||||
|
...form.value,
|
||||||
|
planList: result.data // 使用清洗后的数据
|
||||||
|
});
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
|
// 6. 刷新列表
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('操作失败,请重试');
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除批次 */
|
/** 删除批次 */
|
||||||
const handleDeleteBatch = async () => {
|
const handleDeleteBatch = async () => {
|
||||||
const _ids = batchTreeRef.value.getCurrentNode()?.id;
|
const _id = batchTreeRef.value?.getCurrentNode()?.id;
|
||||||
await proxy?.$modal.confirm('是否确认删除批次编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
if (!_id) {
|
||||||
await delBatch(_ids);
|
return proxy?.$modal.msgError('请先选择批次');
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
}
|
||||||
queryParams.value.mainData.mrpBaseId = undefined;
|
|
||||||
await getList();
|
try {
|
||||||
|
await proxy?.$modal.confirm('是否确认删除该批次?删除后不可恢复!');
|
||||||
|
await delBatch(_id);
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
// 重置选中状态并刷新列表
|
||||||
|
queryParams.value.mainData.mrpBaseId = undefined;
|
||||||
|
form.value.mrpBaseBo.status = undefined;
|
||||||
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
// 取消确认时不提示错误
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
proxy?.$modal.msgError('删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ValidateResult {
|
/** 数据清洗与基础校验 */
|
||||||
valid: boolean;
|
function validateAndClean(arr: PlanListItem[]) {
|
||||||
data: any[];
|
// 1. 过滤掉全空的数据项
|
||||||
errors: { index: number; field: string; message: string }[];
|
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null || v === undefined));
|
||||||
}
|
|
||||||
|
|
||||||
function validateAndClean(arr: any[]) {
|
let hasFullItem = false; // 是否有至少一条完整数据
|
||||||
// 过滤掉全空的数据项
|
|
||||||
const cleanedArr = arr.filter((item) => !Object.values(item).every((v) => v === '' || v == null));
|
|
||||||
|
|
||||||
let hasFullItem = false; // 是否有至少一条全填数据
|
|
||||||
|
|
||||||
|
// 2. 逐行校验必填项
|
||||||
for (let idx = 0; idx < cleanedArr.length; idx++) {
|
for (let idx = 0; idx < cleanedArr.length; idx++) {
|
||||||
const item = cleanedArr[idx];
|
const item = cleanedArr[idx];
|
||||||
const keys = Object.keys(item).filter((k) => k !== 'remark' && k !== 'id');
|
|
||||||
|
|
||||||
const allFilled = keys.every((k) => item[k] !== '' && item[k] != null);
|
// 校验版本号
|
||||||
const allEmpty = Object.values(item).every((v) => v === '' || v == null);
|
if (!item.versions) {
|
||||||
|
return { valid: false, message: `第${idx + 1}行:版本号不能为空`, data: cleanedArr };
|
||||||
|
}
|
||||||
|
|
||||||
// 单独检查 qs 和 arrivalTime
|
// 校验物资选择
|
||||||
|
if (!item.suppliespriceId) {
|
||||||
|
return { valid: false, message: `第${idx + 1}行:请选择物资名称`, data: cleanedArr };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验质量标准
|
||||||
if (!item.qs) {
|
if (!item.qs) {
|
||||||
return { valid: false, message: `第${idx + 1}行:质量标准不能为空`, data: cleanedArr };
|
return { valid: false, message: `第${idx + 1}行:质量标准不能为空`, data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 校验需求到货时间
|
||||||
if (!item.arrivalTime) {
|
if (!item.arrivalTime) {
|
||||||
return { valid: false, message: `第${idx + 1}行:需求到货时间不能为空`, data: cleanedArr };
|
return { valid: false, message: `第${idx + 1}行:需求到货时间不能为空`, data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查其他字段是否部分填
|
// 校验数量(必填且≥0)
|
||||||
if (!allFilled && !allEmpty) {
|
if (item.demandQuantity === null || item.demandQuantity === undefined || item.demandQuantity < 0) {
|
||||||
return { valid: false, message: `第${idx + 1}行:主要信息存在部分字段缺失的数据项`, data: cleanedArr };
|
return { valid: false, message: `第${idx + 1}行:请输入合法的需求数量`, data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allFilled) {
|
hasFullItem = true;
|
||||||
hasFullItem = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否至少有一条完整的数据
|
// 3. 检查是否至少有一条完整数据
|
||||||
if (!hasFullItem) {
|
if (!hasFullItem) {
|
||||||
return { valid: false, message: '至少需要一条完整的数据', data: cleanedArr };
|
return { valid: false, message: '至少需要填写一条完整的物资数据', data: cleanedArr };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { valid: true, message: '', data: cleanedArr };
|
return { valid: true, message: '', data: cleanedArr };
|
||||||
@ -506,54 +720,95 @@ function validateAndClean(arr: any[]) {
|
|||||||
/** 审核按钮操作 */
|
/** 审核按钮操作 */
|
||||||
const handleAudit = async () => {
|
const handleAudit = async () => {
|
||||||
if (!form.value.mrpBaseBo.status) {
|
if (!form.value.mrpBaseBo.status) {
|
||||||
proxy?.$modal.msgError('请选择批次号');
|
return proxy?.$modal.msgError('请选择批次号');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (!queryParams.value.mainData.mrpBaseId) {
|
||||||
|
return proxy?.$modal.msgError('请选择批次号');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭当前页并打开审核页
|
||||||
proxy?.$tab.closePage(route);
|
proxy?.$tab.closePage(route);
|
||||||
proxy?.$tab.openPage('/approval/batchPlan/indexEdit', '审核物资设备批次需求计划', {
|
proxy?.$tab.openPage('/approval/batchPlan/indexEdit', '审核物资设备批次需求计划', {
|
||||||
id: queryParams.value.mainData.mrpBaseId,
|
id: queryParams.value.mainData.mrpBaseId,
|
||||||
status: form.value.mrpBaseBo.status + '_batchRequirements',
|
status: `${form.value.mrpBaseBo.status}_batchRequirements`,
|
||||||
type: 'update'
|
type: 'update'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNameList = (versions) => {
|
/** 获取物资列表(按版本号筛选) */
|
||||||
coryEngineeringList({ projectId: currentProject.value?.id, versions }).then((res) => {
|
const getNameList = (versions: string) => {
|
||||||
nameList.value = res.data;
|
coryEngineeringList({
|
||||||
});
|
projectId: currentProject.value?.id,
|
||||||
};
|
versions
|
||||||
// 获取版本号
|
})
|
||||||
const getVersion = () => {
|
.then((res: any) => {
|
||||||
obtainTheVersion({ projectId: currentProject.value?.id }).then((res) => {
|
nameList.value = res.data || [];
|
||||||
versionList.value = res.data;
|
})
|
||||||
});
|
.catch(() => {
|
||||||
};
|
nameList.value = [];
|
||||||
const selectNameVersion = (val, row) => {
|
proxy?.$modal.msgError('获取物资列表失败');
|
||||||
row.suppliespriceId = undefined;
|
});
|
||||||
getNameList(val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 获取版本号列表 */
|
||||||
|
const getVersion = () => {
|
||||||
|
obtainTheVersion({ projectId: currentProject.value?.id })
|
||||||
|
.then((res: any) => {
|
||||||
|
versionList.value = res.data || [];
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
versionList.value = [];
|
||||||
|
proxy?.$modal.msgError('获取版本号失败');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选择版本号触发(新增索引参数,用于触发重复校验) */
|
||||||
|
const selectNameVersion = (val: string, row: PlanListItem, index: number) => {
|
||||||
|
row.versions = val;
|
||||||
|
row.suppliespriceId = undefined; // 切换版本号时清空物资选择
|
||||||
|
row.name = undefined;
|
||||||
|
row.specification = undefined;
|
||||||
|
row.unit = undefined;
|
||||||
|
row.qs = undefined;
|
||||||
|
row.remark = undefined;
|
||||||
|
row.arrivalTime = undefined;
|
||||||
|
row.demandQuantity = undefined;
|
||||||
|
row.quantityError = '';
|
||||||
|
row.duplicateError = '';
|
||||||
|
|
||||||
|
// 1. 获取对应版本的物资列表
|
||||||
|
getNameList(val);
|
||||||
|
|
||||||
|
// 2. 触发重复校验(清空物资后可能消除重复)
|
||||||
|
checkDuplicate();
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 页面挂载时初始化 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
// getNameList();
|
|
||||||
getVersion();
|
getVersion();
|
||||||
});
|
});
|
||||||
|
|
||||||
//监听项目id刷新数据
|
/** 监听项目ID变化,刷新数据 */
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(newId, oldId) => {
|
||||||
queryParams.value.mainData.projectId = nid;
|
if (newId !== oldId && newId) {
|
||||||
queryParams.value.batchData.projectId = nid;
|
queryParams.value.mainData.projectId = newId;
|
||||||
form.value.mrpBaseBo.projectId = nid;
|
queryParams.value.batchData.projectId = newId;
|
||||||
getList();
|
form.value.mrpBaseBo.projectId = newId;
|
||||||
|
getList();
|
||||||
|
getVersion(); // 重新获取对应项目的版本号
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 页面卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.custom-tree-node {
|
.custom-tree-node {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -563,4 +818,17 @@ onUnmounted(() => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-right: 8px;
|
padding-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 错误提示样式补充 */
|
||||||
|
.text-red-500 {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-xs {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -156,18 +156,38 @@
|
|||||||
<el-form-item
|
<el-form-item
|
||||||
label="库存"
|
label="库存"
|
||||||
:prop="`itemList.${index}.stockQuantity`"
|
:prop="`itemList.${index}.stockQuantity`"
|
||||||
:rules="[{ required: true, message: '库存不能为空', trigger: 'blur' }]"
|
:rules="[
|
||||||
|
{ required: true, message: '库存不能为空', trigger: 'blur' },
|
||||||
|
{ type: 'number', min: 0, message: '库存不能小于0', trigger: ['blur', 'change'] }
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.stockQuantity" placeholder="请输入库存" />
|
<el-input
|
||||||
|
v-model.number="item.stockQuantity"
|
||||||
|
placeholder="请输入库存"
|
||||||
|
@input="handleStockChange(index)"
|
||||||
|
@blur="handleStockChange(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="领取"
|
label="领取"
|
||||||
:prop="`itemList.${index}.issuedQuantity`"
|
:prop="`itemList.${index}.issuedQuantity`"
|
||||||
:rules="[{ required: true, message: '领取数量不能为空', trigger: 'blur' }]"
|
:rules="[
|
||||||
|
{ required: true, message: '领取数量不能为空', trigger: 'blur' },
|
||||||
|
{ type: 'number', min: 0, message: '领取数量不能小于0', trigger: ['blur', 'change'] },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => validateIssuedQuantity(rule, value, callback, index),
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.issuedQuantity" placeholder="请输入领取数量" />
|
<el-input
|
||||||
|
v-model.number="item.issuedQuantity"
|
||||||
|
placeholder="请输入领取数量"
|
||||||
|
@input="handleIssuedChange(index)"
|
||||||
|
@blur="handleIssuedChange(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -176,7 +196,7 @@
|
|||||||
:prop="`itemList.${index}.remainingQuantity`"
|
:prop="`itemList.${index}.remainingQuantity`"
|
||||||
:rules="[{ required: true, message: '剩余数量不能为空', trigger: 'blur' }]"
|
:rules="[{ required: true, message: '剩余数量不能为空', trigger: 'blur' }]"
|
||||||
>
|
>
|
||||||
<el-input v-model="item.remainingQuantity" placeholder="请输入剩余数量" />
|
<el-input v-model.number="item.remainingQuantity" placeholder="请输入剩余数量" readonly />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -248,6 +268,9 @@ import {
|
|||||||
import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types';
|
import { MaterialIssueVO, MaterialIssueQuery, MaterialIssueForm } from '@/api/materials/materialIssue/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
import wordllssue from './word/index.vue';
|
import wordllssue from './word/index.vue';
|
||||||
|
import { watch, onMounted, onUnmounted, ref, reactive, computed, getCurrentInstance } from 'vue';
|
||||||
|
import type { ComponentInternalInstance, ElFormInstance, DialogOption } from 'element-plus';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
// 获取用户 store
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
@ -265,6 +288,8 @@ const total = ref(0);
|
|||||||
const wordllssueRef = ref<InstanceType<typeof wordllssue>>();
|
const wordllssueRef = ref<InstanceType<typeof wordllssue>>();
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const materialIssueFormRef = ref<ElFormInstance>();
|
const materialIssueFormRef = ref<ElFormInstance>();
|
||||||
|
// 存储每个条目的watch停止函数
|
||||||
|
const itemWatchStopFns = ref<Array<() => void>>([]);
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
@ -303,12 +328,14 @@ const getInitFormData = () => {
|
|||||||
issuedQuantity: undefined,
|
issuedQuantity: undefined,
|
||||||
remainingQuantity: undefined,
|
remainingQuantity: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
|
materialsId: undefined
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
const data = reactive<PageData<MaterialIssueForm, MaterialIssueQuery>>({
|
|
||||||
|
const data = reactive({
|
||||||
form: getInitFormData(),
|
form: getInitFormData(),
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
@ -326,7 +353,13 @@ const data = reactive<PageData<MaterialIssueForm, MaterialIssueQuery>>({
|
|||||||
params: {}
|
params: {}
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键id不能为空', trigger: 'blur' }]
|
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
|
||||||
|
projectName: [{ required: true, message: '请输入工程名称', trigger: 'blur' }],
|
||||||
|
materialName: [{ required: true, message: '请输入设备材料名称', trigger: 'blur' }],
|
||||||
|
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }],
|
||||||
|
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
|
||||||
|
issueUnit: [{ required: true, message: '请输入领料单位', trigger: 'blur' }],
|
||||||
|
storageUnit: [{ required: true, message: '请输入保管单位', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -335,34 +368,94 @@ const { queryParams, form, rules } = toRefs(data);
|
|||||||
/** 查询物料领料单列表 */
|
/** 查询物料领料单列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await listMaterialIssue(queryParams.value);
|
try {
|
||||||
materialIssueList.value = res.rows;
|
const res = await listMaterialIssue(queryParams.value);
|
||||||
total.value = res.total;
|
materialIssueList.value = res.rows;
|
||||||
loading.value = false;
|
total.value = res.total;
|
||||||
};
|
} finally {
|
||||||
const optionsName: any = ref([]);
|
loading.value = false;
|
||||||
|
|
||||||
//获取一起名称
|
|
||||||
const getName = async () => {
|
|
||||||
const res = await getMaterialName(currentProject.value.id);
|
|
||||||
console.log(res);
|
|
||||||
if (res.code == 200) {
|
|
||||||
optionsName.value = res.data;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const optionsName: any = ref([]);
|
||||||
|
|
||||||
|
// 获取材料名称列表
|
||||||
|
const getName = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getMaterialName(currentProject.value.id);
|
||||||
|
if (res.code == 200) {
|
||||||
|
optionsName.value = res.data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取材料名称失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 材料名称选择变化处理
|
||||||
const getNameChange = (value, index, item) => {
|
const getNameChange = (value, index, item) => {
|
||||||
// 这里可以添加处理逻辑
|
|
||||||
console.log(value);
|
|
||||||
|
|
||||||
const data = optionsName.value.find((item) => item.id == value);
|
const data = optionsName.value.find((item) => item.id == value);
|
||||||
console.log(data);
|
if (data) {
|
||||||
|
form.value.itemList[index].name = data.materialsName;
|
||||||
|
form.value.itemList[index].materialsId = data.id;
|
||||||
|
form.value.itemList[index].specification = data.typeSpecificationName;
|
||||||
|
form.value.itemList[index].unit = data.weightId;
|
||||||
|
form.value.itemList[index].stockQuantity = data.inventoryNumber;
|
||||||
|
// 触发剩余数量计算
|
||||||
|
calculateRemaining(index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
form.value.itemList[index].name = data.materialsName;
|
/** 验证领取数量不能超过库存 */
|
||||||
form.value.itemList[index].materialsId = data.id;
|
const validateIssuedQuantity = (rule, value, callback, index) => {
|
||||||
form.value.itemList[index].specification = data.typeSpecificationName;
|
const item = form.value.itemList[index];
|
||||||
form.value.itemList[index].unit = data.weightId;
|
const stock = Number(item.stockQuantity) || 0;
|
||||||
form.value.itemList[index].stockQuantity = data.inventoryNumber;
|
const issued = Number(value) || 0;
|
||||||
|
|
||||||
|
if (stock === 0) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issued > stock) {
|
||||||
|
callback(new Error(`领取数量不能超过库存(${stock})`));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 计算剩余数量(库存 - 领取数量) */
|
||||||
|
const calculateRemaining = (index: number) => {
|
||||||
|
const item = form.value.itemList[index];
|
||||||
|
const stock = Number(item.stockQuantity) || 0;
|
||||||
|
const issued = Number(item.issuedQuantity) || 0;
|
||||||
|
|
||||||
|
// 确保领取数量不超过库存
|
||||||
|
if (issued > stock) {
|
||||||
|
item.issuedQuantity = stock;
|
||||||
|
proxy?.$modal.msgWarning(`领取数量不能超过库存(${stock}),已自动调整`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算剩余数量
|
||||||
|
item.remainingQuantity = stock - (item.issuedQuantity || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 库存变化时重新计算剩余数量 */
|
||||||
|
const handleStockChange = (index: number) => {
|
||||||
|
calculateRemaining(index);
|
||||||
|
// 触发验证
|
||||||
|
if (materialIssueFormRef.value) {
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.issuedQuantity`);
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 领取数量变化时重新计算剩余数量 */
|
||||||
|
const handleIssuedChange = (index: number) => {
|
||||||
|
calculateRemaining(index);
|
||||||
|
// 触发验证
|
||||||
|
if (materialIssueFormRef.value) {
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
@ -373,8 +466,36 @@ const cancel = () => {
|
|||||||
|
|
||||||
/** 表单重置 */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
|
// 停止所有监听
|
||||||
|
itemWatchStopFns.value.forEach((stop) => stop());
|
||||||
|
itemWatchStopFns.value = [];
|
||||||
|
|
||||||
form.value = getInitFormData();
|
form.value = getInitFormData();
|
||||||
materialIssueFormRef.value?.resetFields();
|
materialIssueFormRef.value?.resetFields();
|
||||||
|
|
||||||
|
// 重新监听初始条目
|
||||||
|
if (form.value.itemList.length > 0) {
|
||||||
|
watchItemChanges(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 监听条目变化,自动计算剩余数量 */
|
||||||
|
const watchItemChanges = (index: number) => {
|
||||||
|
// 停止已有监听
|
||||||
|
if (itemWatchStopFns.value[index]) {
|
||||||
|
itemWatchStopFns.value[index]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听库存和领取数量变化
|
||||||
|
const stop = watch(
|
||||||
|
() => [form.value.itemList[index].stockQuantity, form.value.itemList[index].issuedQuantity],
|
||||||
|
() => {
|
||||||
|
calculateRemaining(index);
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
itemWatchStopFns.value[index] = stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
@ -407,10 +528,42 @@ const handleAdd = () => {
|
|||||||
const handleUpdate = async (row?: MaterialIssueVO) => {
|
const handleUpdate = async (row?: MaterialIssueVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getMaterialIssue(_id);
|
try {
|
||||||
Object.assign(form.value, res.data);
|
const res = await getMaterialIssue(_id);
|
||||||
dialog.visible = true;
|
Object.assign(form.value, res.data);
|
||||||
dialog.title = '修改物料领料单';
|
|
||||||
|
// 确保itemList存在
|
||||||
|
if (!form.value.itemList) {
|
||||||
|
form.value.itemList = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换数据类型并计算剩余数量(关键修复)
|
||||||
|
form.value.itemList = form.value.itemList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
stockQuantity: Number(item.stockQuantity) || 0,
|
||||||
|
issuedQuantity: Number(item.issuedQuantity) || 0,
|
||||||
|
remainingQuantity: Number(item.remainingQuantity) || 0
|
||||||
|
}));
|
||||||
|
|
||||||
|
// 为每个条目添加监听并强制计算剩余数量
|
||||||
|
form.value.itemList.forEach((_, index) => {
|
||||||
|
watchItemChanges(index);
|
||||||
|
calculateRemaining(index); // 强制计算确保数据一致性
|
||||||
|
});
|
||||||
|
// 手动触发一次验证(关键修复)
|
||||||
|
setTimeout(() => {
|
||||||
|
if (materialIssueFormRef.value) {
|
||||||
|
form.value.itemList.forEach((_, index) => {
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.issuedQuantity`);
|
||||||
|
materialIssueFormRef.value.validateField(`itemList.${index}.remainingQuantity`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '修改物料领料单';
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('获取详情失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
@ -418,21 +571,38 @@ const submitForm = () => {
|
|||||||
materialIssueFormRef.value?.validate(async (valid: boolean) => {
|
materialIssueFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
if (form.value.id) {
|
try {
|
||||||
await updateMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
|
// 处理提交数据,确保数量为数字类型
|
||||||
} else {
|
const submitData = {
|
||||||
await addMaterialIssue(form.value).finally(() => (buttonLoading.value = false));
|
...form.value,
|
||||||
|
itemList: form.value.itemList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
stockQuantity: Number(item.stockQuantity),
|
||||||
|
issuedQuantity: Number(item.issuedQuantity),
|
||||||
|
remainingQuantity: Number(item.remainingQuantity)
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
if (form.value.id) {
|
||||||
|
await updateMaterialIssue(submitData);
|
||||||
|
} else {
|
||||||
|
await addMaterialIssue(submitData);
|
||||||
|
}
|
||||||
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
|
dialog.visible = false;
|
||||||
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
proxy?.$modal.msgError('操作失败');
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
|
||||||
dialog.visible = false;
|
|
||||||
await getList();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加数量验收条目
|
// 添加数量验收条目
|
||||||
const addItem = () => {
|
const addItem = () => {
|
||||||
form.value.itemList.push({
|
const newItem = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
@ -440,46 +610,68 @@ const addItem = () => {
|
|||||||
issuedQuantity: undefined,
|
issuedQuantity: undefined,
|
||||||
remainingQuantity: undefined,
|
remainingQuantity: undefined,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
remark: undefined
|
remark: undefined,
|
||||||
});
|
materialsId: undefined
|
||||||
|
};
|
||||||
|
form.value.itemList.push(newItem);
|
||||||
|
// 监听新条目
|
||||||
|
watchItemChanges(form.value.itemList.length - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除数量验收条目
|
// 删除数量验收条目
|
||||||
const removeItem = (index: number) => {
|
const removeItem = (index: number) => {
|
||||||
if (form.value.itemList.length > 1) {
|
if (form.value.itemList.length > 1) {
|
||||||
|
// 停止该条目的监听
|
||||||
|
if (itemWatchStopFns.value[index]) {
|
||||||
|
itemWatchStopFns.value[index]();
|
||||||
|
}
|
||||||
form.value.itemList.splice(index, 1);
|
form.value.itemList.splice(index, 1);
|
||||||
|
itemWatchStopFns.value.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (row?: MaterialIssueVO) => {
|
const handleDelete = async (row?: MaterialIssueVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除物料领料单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
try {
|
||||||
await delMaterialIssue(_ids);
|
await proxy?.$modal.confirm(`是否确认删除物料领料单编号为"${_ids}"的数据项?`);
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
await delMaterialIssue(_ids);
|
||||||
await getList();
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
await getList();
|
||||||
|
} catch (error) {
|
||||||
|
// 取消删除不提示
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleView = (row) => {
|
const handleView = (row) => {
|
||||||
// 查看详情
|
// 查看详情
|
||||||
wordllssueRef.value?.openDialog(row);
|
wordllssueRef.value?.openDialog(row);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
getName();
|
getName();
|
||||||
});
|
});
|
||||||
//监听项目id刷新数据
|
|
||||||
|
// 监听项目id刷新数据
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(nid) => {
|
||||||
queryParams.value.projectId = nid;
|
queryParams.value.projectId = nid;
|
||||||
form.value.projectId = nid;
|
form.value.projectId = nid;
|
||||||
getList();
|
getList();
|
||||||
|
getName();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
|
// 清理所有监听
|
||||||
|
itemWatchStopFns.value.forEach((stop) => stop());
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@ -57,16 +57,15 @@
|
|||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="操作" align="center" min-width="120" fixed="right">
|
<el-table-column label="操作" align="center" min-width="120" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip content="查看" placement="top">
|
<!-- <el-button link type="primary" icon="edit" @click="handleUpdate(scope.row)" v-hasPermi="['materials:materialReceive:edit']"
|
||||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialReceive:query']"
|
>修改</el-button
|
||||||
>查看</el-button
|
> -->
|
||||||
>
|
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['materials:materialReceive:query']"
|
||||||
</el-tooltip>
|
>查看</el-button
|
||||||
<el-tooltip content="删除" placement="top">
|
>
|
||||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialReceive:remove']"
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['materials:materialReceive:remove']"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
>
|
>
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -74,7 +73,15 @@
|
|||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 添加或修改物料接收单对话框 -->
|
<!-- 添加或修改物料接收单对话框 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
|
<el-dialog
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
draggable
|
||||||
|
:title="dialog.title"
|
||||||
|
v-model="dialog.visible"
|
||||||
|
width="800px"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
|
<el-form ref="materialReceiveFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -122,7 +129,6 @@
|
|||||||
:value="item.contractCode"
|
:value="item.contractCode"
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<!-- <el-input v-model="form.contractName" placeholder="请输入合同名称" /> -->
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@ -131,14 +137,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<!-- 数量验收区域(修复v-for key问题) -->
|
<!-- 数量验收区域 -->
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<div class="detail-header">
|
<div class="detail-header">
|
||||||
<span>数量验收</span>
|
<span>数量验收</span>
|
||||||
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
|
<el-button type="primary" v-if="form.materialSource == '1'" link @click="addItem" icon="Plus">添加数量验收</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 关键修复:v-for key改为item.id(唯一标识),而非index -->
|
|
||||||
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
<div v-for="(item, index) in form.itemList" :key="item.id" class="detail-item">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -161,21 +166,27 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item label="数量" :prop="`itemList.${index}.quantity`" :rules="rules.quantityRule" ref="quantityFormItemRefs[index]">
|
||||||
label="数量"
|
<el-input
|
||||||
:prop="`itemList.${index}.quantity`"
|
:disabled="form.materialSource == '2'"
|
||||||
:rules="{ required: true, message: '数量不能为空', trigger: 'blur' }"
|
type="number"
|
||||||
>
|
v-model.number="item.quantity"
|
||||||
<el-input :disabled="form.materialSource == '2'" type="number" v-model="item.quantity" placeholder="请输入数量" />
|
placeholder="请输入数量"
|
||||||
|
min="0"
|
||||||
|
@input="handleQuantityInput(index)"
|
||||||
|
@blur="handleQuantityBlur(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item label="验收" :prop="`itemList.${index}.acceptedQuantity`" :rules="rules.acceptedQuantityRule">
|
||||||
label="验收"
|
<el-input
|
||||||
:prop="`itemList.${index}.acceptedQuantity`"
|
type="number"
|
||||||
:rules="{ required: true, message: '验收数量不能为空', trigger: 'blur' }"
|
v-model.number="item.acceptedQuantity"
|
||||||
>
|
placeholder="请输入验收"
|
||||||
<el-input type="number" v-model="item.acceptedQuantity" placeholder="请输入验收" />
|
min="0"
|
||||||
|
@input="handleAcceptedInput(index)"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -184,13 +195,13 @@
|
|||||||
:prop="`itemList.${index}.shortageQuantity`"
|
:prop="`itemList.${index}.shortageQuantity`"
|
||||||
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
|
:rules="{ required: true, message: '缺件数量不能为空', trigger: 'blur' }"
|
||||||
>
|
>
|
||||||
<el-input type="number" v-model="item.shortageQuantity" placeholder="自动计算(数量-验收数量)" readonly />
|
<el-input type="number" min="0" v-model="item.shortageQuantity" placeholder="自动计算" readonly />
|
||||||
<span class="tips">*自动计算(数量-验收数量)</span>
|
<span class="tips">*自动计算(数量-验收数量)</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
|
<el-form-item label="备注" :prop="`itemList.${index}.remark`">
|
||||||
<el-input v-model="item.remark" placeholder="请输入备注" />
|
<el-input v-model="item.remark" type="textarea" placeholder="请输入备注" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.itemList.length > 1 && form.materialSource == '1'">
|
<el-col :span="12" v-if="form.itemList.length > 1 && form.materialSource == '1'">
|
||||||
@ -205,26 +216,26 @@
|
|||||||
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="合格证文件" prop="certCountFileId">
|
<el-form-item label="合格证文件" prop="certCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.certCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.certCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="出厂报告文件" prop="reportCountFileId">
|
<el-form-item label="出厂报告文件" prop="reportCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.reportCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.reportCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="技术资料文件" prop="techDocCountFileId">
|
<el-form-item label="技术资料文件" prop="techDocCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.techDocCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.techDocCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
|
<el-form-item label="厂家资质文件" prop="licenseCountFileId">
|
||||||
<file-upload :isShowTip="false" v-model="form.licenseCountFileId" />
|
<file-upload :isShowTip="false" :fileType="['pdf', 'png', 'jpg', 'jpeg']" v-model="form.licenseCountFileId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意:请上传doc/xls/ppt/txt/pdf/png/jpg/jpeg/zip格式文件</span>
|
<span style="color: #ff0000ab; margin-bottom: 10px; display: block">注意:pdf/png/jpg/jpeg格式文件</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
@ -258,7 +269,7 @@ import { useUserStoreHook } from '@/store/modules/user';
|
|||||||
import wordllReceive from './word/index.vue';
|
import wordllReceive from './word/index.vue';
|
||||||
import { listPurchaseDoc, purchaseDocPlanList } from '@/api/materials/purchaseDoc';
|
import { listPurchaseDoc, purchaseDocPlanList } from '@/api/materials/purchaseDoc';
|
||||||
import { watch, onMounted, onUnmounted, ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
|
import { watch, onMounted, onUnmounted, ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
|
||||||
import type { ComponentInternalInstance, ElFormInstance, DialogOption } from 'element-plus';
|
import type { ComponentInternalInstance, ElFormInstance, DialogOption, ElFormItem } from 'element-plus';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
const { storage_type } = toRefs<any>(proxy?.useDict('storage_type'));
|
const { storage_type } = toRefs<any>(proxy?.useDict('storage_type'));
|
||||||
@ -266,8 +277,10 @@ const userStore = useUserStoreHook();
|
|||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
const wordllReceiveRef = ref<InstanceType<typeof wordllReceive>>();
|
const wordllReceiveRef = ref<InstanceType<typeof wordllReceive>>();
|
||||||
|
|
||||||
// 核心修复1:存储每个验收条目的watch停止函数,避免内存泄漏
|
// 存储每个验收条目的watch停止函数
|
||||||
const itemWatchStopFns = ref<Array<() => void>>([]);
|
const itemWatchStopFns = ref<Array<() => void>>([]);
|
||||||
|
// 存储数量表单项的引用,用于手动触发验证
|
||||||
|
const quantityFormItemRefs = ref<(ElFormItem | null)[]>([]);
|
||||||
|
|
||||||
// 列表数据
|
// 列表数据
|
||||||
const materialReceiveList = ref<MaterialReceiveVO[]>([]);
|
const materialReceiveList = ref<MaterialReceiveVO[]>([]);
|
||||||
@ -285,18 +298,19 @@ const materialReceiveFormRef = ref<ElFormInstance>();
|
|||||||
const purchaseDocList = ref([]); // 物资采购单列表
|
const purchaseDocList = ref([]); // 物资采购单列表
|
||||||
const purchaseMap = new Map(); // 采购单映射(id -> 采购单对象)
|
const purchaseMap = new Map(); // 采购单映射(id -> 采购单对象)
|
||||||
const contractNameList = ref([]); //合同列表
|
const contractNameList = ref([]); //合同列表
|
||||||
|
|
||||||
// 对话框配置
|
// 对话框配置
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// 生成验收条目唯一ID(用于v-for key)
|
// 生成验收条目唯一ID
|
||||||
const generateItemId = () => {
|
const generateItemId = () => {
|
||||||
return Date.now() + Math.random().toString(36).substr(2, 9);
|
return Date.now() + Math.random().toString(36).substr(2, 9);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化表单数据(修复:给验收条目添加唯一ID)
|
// 初始化表单数据
|
||||||
const getInitFormData = (): MaterialReceiveForm => {
|
const getInitFormData = (): MaterialReceiveForm => {
|
||||||
return {
|
return {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
@ -323,7 +337,7 @@ const getInitFormData = (): MaterialReceiveForm => {
|
|||||||
docCode: undefined,
|
docCode: undefined,
|
||||||
itemList: [
|
itemList: [
|
||||||
{
|
{
|
||||||
id: generateItemId(), // 新增:唯一ID,解决v-for渲染问题
|
id: generateItemId(),
|
||||||
name: undefined,
|
name: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
@ -357,7 +371,38 @@ const data = reactive({
|
|||||||
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
|
formCode: [{ required: true, message: '请输入表单编号', trigger: 'blur' }],
|
||||||
docId: [{ required: true, message: '请选择物资采购单', trigger: 'change' }],
|
docId: [{ required: true, message: '请选择物资采购单', trigger: 'change' }],
|
||||||
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
|
supplierUnit: [{ required: true, message: '请输入供货单位', trigger: 'blur' }],
|
||||||
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }]
|
orderingUnit: [{ required: true, message: '请输入订货单位', trigger: 'blur' }],
|
||||||
|
// 数量校验规则:确保触发时机包含change,且类型为number
|
||||||
|
quantityRule: [
|
||||||
|
{ required: true, message: '数量不能为空', trigger: ['blur', 'change'] },
|
||||||
|
{ type: 'number', min: 0, message: '数量不能小于0', trigger: ['blur', 'change'] }
|
||||||
|
],
|
||||||
|
// 验收数量规则(允许≤数量)
|
||||||
|
acceptedQuantityRule: [
|
||||||
|
{ required: true, message: '验收数量不能为空', trigger: ['blur', 'change'] },
|
||||||
|
{ type: 'number', min: 0, message: '验收数量不能小于0', trigger: ['blur', 'change'] },
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const prop = rule.field;
|
||||||
|
const index = Number(prop.split('.')[1]);
|
||||||
|
const quantity = Number(form.value.itemList[index].quantity) || 0;
|
||||||
|
|
||||||
|
// 数量未填写时不验证大小关系;数量有值但验收数量未填时也不阻断(由required规则处理)
|
||||||
|
if (form.value.itemList[index].quantity === undefined || form.value.itemList[index].quantity === null) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 处理value为undefined/null的情况(避免Number(undefined)转为NaN)
|
||||||
|
const acceptedVal = Number(value) || 0;
|
||||||
|
if (acceptedVal > quantity) {
|
||||||
|
callback(new Error('验收数量必须小于等于数量'));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -374,25 +419,29 @@ const getList = async () => {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取合同列表数据
|
// 获取合同列表数据
|
||||||
const getContractList = async () => {
|
const getContractList = async () => {
|
||||||
let res = await getContractNameList(currentProject.value?.id);
|
let res = await getContractNameList(currentProject.value?.id);
|
||||||
contractNameList.value = res.rows;
|
contractNameList.value = res.rows;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 取消按钮 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 表单重置(修复:清理验收条目监听) */
|
/** 表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
// 停止所有验收条目的watch监听
|
// 停止所有验收条目的watch监听
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
itemWatchStopFns.value = [];
|
itemWatchStopFns.value = [];
|
||||||
|
|
||||||
form.value = getInitFormData();
|
form.value = getInitFormData();
|
||||||
materialReceiveFormRef.value?.resetFields();
|
if (materialReceiveFormRef.value) {
|
||||||
|
materialReceiveFormRef.value.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
// 重新监听初始条目
|
// 重新监听初始条目
|
||||||
if (form.value.itemList.length > 0) {
|
if (form.value.itemList.length > 0) {
|
||||||
@ -408,7 +457,9 @@ const handleQuery = () => {
|
|||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 重置按钮操作 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
if (queryFormRef.value) {
|
||||||
|
queryFormRef.value.resetFields();
|
||||||
|
}
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -427,24 +478,35 @@ const handleAdd = () => {
|
|||||||
form.value.projectName = currentProject.value?.name;
|
form.value.projectName = currentProject.value?.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作(修复:清理旧监听+添加唯一ID) */
|
/** 修改按钮操作(核心修复:赋值后主动触发验证+数据类型转换) */
|
||||||
const handleUpdate = async (row?: MaterialReceiveVO) => {
|
const handleUpdate = async (row?: MaterialReceiveVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await getMaterialReceive(_id);
|
const res = await getMaterialReceive(_id);
|
||||||
// 给验收条目补充唯一ID(避免后端返回无ID)
|
|
||||||
const formData = res.data;
|
const formData = res.data;
|
||||||
|
|
||||||
|
// 修复1:处理itemList数据类型,确保数量/验收数量为数字(避免字符串与number规则冲突)
|
||||||
formData.itemList = formData.itemList.map((item) => ({
|
formData.itemList = formData.itemList.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
id: item.id || generateItemId()
|
id: item.id || generateItemId(),
|
||||||
|
quantity: item.quantity !== undefined ? Number(item.quantity) : undefined, // 转为数字
|
||||||
|
acceptedQuantity: item.acceptedQuantity !== undefined ? Number(item.acceptedQuantity) : undefined, // 转为数字
|
||||||
|
shortageQuantity: item.shortageQuantity !== undefined ? Number(item.shortageQuantity) : undefined // 转为数字
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Object.assign(form.value, formData);
|
Object.assign(form.value, formData);
|
||||||
|
|
||||||
// 重新监听所有条目
|
// 修复2:重新监听所有条目,并主动触发每个条目的验证(更新验证状态)
|
||||||
form.value.itemList.forEach((_, index) => {
|
form.value.itemList.forEach((_, index) => {
|
||||||
watchItemChanges(index);
|
watchItemChanges(index);
|
||||||
|
// 手动触发当前条目的数量、验收数量、缺件数量验证
|
||||||
|
if (materialReceiveFormRef.value) {
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.quantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.acceptedQuantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.shortageQuantity`, () => {});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
@ -460,13 +522,24 @@ const submitForm = () => {
|
|||||||
if (valid) {
|
if (valid) {
|
||||||
buttonLoading.value = true;
|
buttonLoading.value = true;
|
||||||
try {
|
try {
|
||||||
|
// 提交前确保数据类型正确(数字)
|
||||||
|
const submitForm = {
|
||||||
|
...form.value,
|
||||||
|
itemList: form.value.itemList.map((item) => ({
|
||||||
|
...item,
|
||||||
|
quantity: Number(item.quantity),
|
||||||
|
acceptedQuantity: Number(item.acceptedQuantity),
|
||||||
|
shortageQuantity: Number(item.shortageQuantity)
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateMaterialReceive({ ...form.value });
|
await updateMaterialReceive(submitForm);
|
||||||
} else {
|
} else {
|
||||||
form.value.itemList.forEach((item) => {
|
submitForm.itemList.forEach((item) => {
|
||||||
delete item.id;
|
delete item.id;
|
||||||
});
|
});
|
||||||
await addMaterialReceive({ ...form.value });
|
await addMaterialReceive(submitForm);
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
@ -495,10 +568,10 @@ const handleDelete = async (row?: MaterialReceiveVO) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 添加数量验收条目(修复:添加唯一ID+监听) */
|
/** 添加数量验收条目 */
|
||||||
const addItem = () => {
|
const addItem = () => {
|
||||||
const newItem = {
|
const newItem = {
|
||||||
id: generateItemId(), // 唯一ID
|
id: generateItemId(),
|
||||||
name: undefined,
|
name: undefined,
|
||||||
specification: undefined,
|
specification: undefined,
|
||||||
unit: undefined,
|
unit: undefined,
|
||||||
@ -508,33 +581,79 @@ const addItem = () => {
|
|||||||
remark: undefined
|
remark: undefined
|
||||||
};
|
};
|
||||||
form.value.itemList.push(newItem);
|
form.value.itemList.push(newItem);
|
||||||
// 监听新条目变化
|
// 监听新条目变化并触发初始验证
|
||||||
watchItemChanges(form.value.itemList.length - 1);
|
watchItemChanges(form.value.itemList.length - 1);
|
||||||
|
validateQuantityField(form.value.itemList.length - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 监听验收条目变化,自动计算缺件数量(修复:存储停止函数) */
|
// 数量输入事件处理
|
||||||
|
const handleQuantityInput = (index: number) => {
|
||||||
|
// 确保值为数字类型
|
||||||
|
if (form.value.itemList[index].quantity !== undefined) {
|
||||||
|
form.value.itemList[index].quantity = Number(form.value.itemList[index].quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动触发验证
|
||||||
|
validateQuantityField(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 数量失焦事件
|
||||||
|
const handleQuantityBlur = (index: number) => {
|
||||||
|
validateQuantityField(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 验收数量输入事件
|
||||||
|
const handleAcceptedInput = (index: number) => {
|
||||||
|
// 确保值为数字类型
|
||||||
|
if (form.value.itemList[index].acceptedQuantity !== undefined) {
|
||||||
|
form.value.itemList[index].acceptedQuantity = Number(form.value.itemList[index].acceptedQuantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 手动触发相关字段验证
|
||||||
|
validateQuantityField(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 手动验证数量和验收数量字段
|
||||||
|
const validateQuantityField = (index: number) => {
|
||||||
|
if (materialReceiveFormRef.value) {
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.quantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.acceptedQuantity`, () => {});
|
||||||
|
materialReceiveFormRef.value.validateField(`itemList.${index}.shortageQuantity`, () => {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听条目变化,自动计算缺件数量(修复:计算后触发验证)
|
||||||
const watchItemChanges = (index: number) => {
|
const watchItemChanges = (index: number) => {
|
||||||
// 停止该索引已有的监听(避免重复监听)
|
|
||||||
if (itemWatchStopFns.value[index]) {
|
if (itemWatchStopFns.value[index]) {
|
||||||
itemWatchStopFns.value[index]();
|
itemWatchStopFns.value[index]();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听数量和验收数量变化
|
|
||||||
const stopFn = watch(
|
const stopFn = watch(
|
||||||
() => [form.value.itemList[index].quantity, form.value.itemList[index].acceptedQuantity],
|
() => [form.value.itemList[index].quantity, form.value.itemList[index].acceptedQuantity],
|
||||||
([quantity, acceptedQuantity]) => {
|
([quantity, acceptedQuantity]) => {
|
||||||
const qty = Number(quantity) || 0;
|
const qty = Number(quantity) || 0;
|
||||||
const acceptedQty = Number(acceptedQuantity) || 0;
|
let acceptedQty = Number(acceptedQuantity) || 0;
|
||||||
|
|
||||||
|
// 仅当验收数量>数量时才修正(允许等于)
|
||||||
|
if (acceptedQty > qty && qty > 0) {
|
||||||
|
acceptedQty = qty; // 修正为数量值(最大合法值)
|
||||||
|
form.value.itemList[index].acceptedQuantity = acceptedQty;
|
||||||
|
proxy?.$modal.msgWarning(`验收数量不能大于数量,已自动修正为${acceptedQty}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算缺件数量(允许为0)
|
||||||
form.value.itemList[index].shortageQuantity = qty - acceptedQty;
|
form.value.itemList[index].shortageQuantity = qty - acceptedQty;
|
||||||
|
|
||||||
|
// 修复3:计算后触发当前条目的验证,确保缺件数量状态更新
|
||||||
|
validateQuantityField(index);
|
||||||
},
|
},
|
||||||
{ immediate: true } // 初始时立即计算
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// 存储停止函数,用于后续删除时清理
|
|
||||||
itemWatchStopFns.value[index] = stopFn;
|
itemWatchStopFns.value[index] = stopFn;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除数量验收条目(修复:清理监听+删除条目) */
|
/** 删除数量验收条目 */
|
||||||
const removeItem = (index: number) => {
|
const removeItem = (index: number) => {
|
||||||
if (form.value.itemList.length <= 1) {
|
if (form.value.itemList.length <= 1) {
|
||||||
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
proxy?.$modal.msgWarning('至少需要保留一条数量验收记录');
|
||||||
@ -549,6 +668,7 @@ const removeItem = (index: number) => {
|
|||||||
// 删除条目和对应的停止函数
|
// 删除条目和对应的停止函数
|
||||||
form.value.itemList.splice(index, 1);
|
form.value.itemList.splice(index, 1);
|
||||||
itemWatchStopFns.value.splice(index, 1);
|
itemWatchStopFns.value.splice(index, 1);
|
||||||
|
quantityFormItemRefs.value.splice(index, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 查看详情 */
|
/** 查看详情 */
|
||||||
@ -564,7 +684,6 @@ const getlistPurchase = async () => {
|
|||||||
status: 'finish'
|
status: 'finish'
|
||||||
});
|
});
|
||||||
purchaseDocList.value = res.rows;
|
purchaseDocList.value = res.rows;
|
||||||
// 构建采购单映射
|
|
||||||
purchaseDocList.value.forEach((item) => {
|
purchaseDocList.value.forEach((item) => {
|
||||||
purchaseMap.set(item.id, item);
|
purchaseMap.set(item.id, item);
|
||||||
});
|
});
|
||||||
@ -573,7 +692,7 @@ const getlistPurchase = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 通过采购单获取需求信息(修复:清理旧监听+添加新监听) */
|
/** 通过采购单获取需求信息(修复:数据类型转换) */
|
||||||
const getdemandInfo = async (docId: string) => {
|
const getdemandInfo = async (docId: string) => {
|
||||||
if (!docId) return;
|
if (!docId) return;
|
||||||
|
|
||||||
@ -583,25 +702,25 @@ const getdemandInfo = async (docId: string) => {
|
|||||||
// 清空旧监听和条目
|
// 清空旧监听和条目
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
itemWatchStopFns.value = [];
|
itemWatchStopFns.value = [];
|
||||||
|
quantityFormItemRefs.value = [];
|
||||||
form.value.itemList = [];
|
form.value.itemList = [];
|
||||||
|
|
||||||
// 赋值需求数据并添加监听
|
// 赋值需求数据并添加监听(确保数量为数字)
|
||||||
res.data.forEach((item, index) => {
|
res.data.forEach((item, index) => {
|
||||||
const qty = Number(item.demandQuantity) || 0;
|
const qty = Number(item.demandQuantity) || 0;
|
||||||
const newItem = {
|
const newItem = {
|
||||||
id: generateItemId(), // 唯一ID
|
id: generateItemId(),
|
||||||
name: item.name,
|
name: item.name,
|
||||||
specification: item.specification,
|
specification: item.specification,
|
||||||
unit: item.unit,
|
unit: item.unit,
|
||||||
quantity: qty,
|
quantity: qty, // 确保数字类型
|
||||||
acceptedQuantity: 0,
|
acceptedQuantity: 0, // 初始值为0(数字)
|
||||||
shortageQuantity: qty, // 初始缺件=总数量
|
shortageQuantity: qty, // 初始缺件=数量(数字)
|
||||||
remark: item.remark,
|
remark: item.remark,
|
||||||
planId: item.id,
|
planId: item.id,
|
||||||
id: null // 保留后端需要的空id字段
|
id: null
|
||||||
};
|
};
|
||||||
form.value.itemList.push(newItem);
|
form.value.itemList.push(newItem);
|
||||||
// 监听当前条目
|
|
||||||
watchItemChanges(index);
|
watchItemChanges(index);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -621,21 +740,25 @@ const handleSelect = (val: string) => {
|
|||||||
form.value.materialName = obj.name || '';
|
form.value.materialName = obj.name || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取采购单对应的需求信息
|
|
||||||
getdemandInfo(val);
|
getdemandInfo(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 核心修复2:监听材料来源变化,重置数量验收列表 */
|
/** 监听材料来源变化,重置数量验收列表 */
|
||||||
watch(
|
watch(
|
||||||
() => form.value.materialSource,
|
() => form.value.materialSource,
|
||||||
(newSource, oldSource) => {
|
(newSource, oldSource) => {
|
||||||
if (newSource === oldSource) return;
|
if (newSource === oldSource) return;
|
||||||
|
|
||||||
// 1. 停止所有验收条目的监听
|
// 停止所有验收条目的监听
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
itemWatchStopFns.value = [];
|
itemWatchStopFns.value = [];
|
||||||
|
quantityFormItemRefs.value = [];
|
||||||
// 2. 重置数量验收列表为初始状态(1条空记录)
|
// 清空所有文件上传字段的值
|
||||||
|
form.value.certCountFileId = undefined; // 合格证文件
|
||||||
|
form.value.reportCountFileId = undefined; // 出厂报告文件
|
||||||
|
form.value.techDocCountFileId = undefined; // 技术资料文件
|
||||||
|
form.value.licenseCountFileId = undefined; // 厂家资质文件
|
||||||
|
// 重置数量验收列表为初始状态
|
||||||
form.value.itemList = [
|
form.value.itemList = [
|
||||||
{
|
{
|
||||||
id: generateItemId(),
|
id: generateItemId(),
|
||||||
@ -649,10 +772,11 @@ watch(
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// 3. 重新监听初始条目
|
// 重新监听初始条目并触发验证
|
||||||
watchItemChanges(0);
|
watchItemChanges(0);
|
||||||
|
validateQuantityField(0);
|
||||||
|
|
||||||
// 4. 切换到乙供时,清空采购单相关数据
|
// 切换到乙供时,清空采购单相关数据
|
||||||
if (newSource === '2') {
|
if (newSource === '2') {
|
||||||
form.value.docId = undefined;
|
form.value.docId = undefined;
|
||||||
form.value.supplierUnit = undefined;
|
form.value.supplierUnit = undefined;
|
||||||
@ -668,9 +792,10 @@ onMounted(() => {
|
|||||||
getContractList();
|
getContractList();
|
||||||
getList();
|
getList();
|
||||||
getlistPurchase();
|
getlistPurchase();
|
||||||
// 监听初始验收条目
|
// 监听初始验收条目并触发验证
|
||||||
if (form.value.itemList.length > 0) {
|
if (form.value.itemList.length > 0) {
|
||||||
watchItemChanges(0);
|
watchItemChanges(0);
|
||||||
|
validateQuantityField(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -689,7 +814,6 @@ const listeningProject = watch(
|
|||||||
/** 页面卸载时清理监听 */
|
/** 页面卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
// 清理验收条目监听
|
|
||||||
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
itemWatchStopFns.value.forEach((stopFn) => stopFn());
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -116,6 +116,9 @@
|
|||||||
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:remove']"
|
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:remove']"
|
||||||
>详情</el-button
|
>详情</el-button
|
||||||
>
|
>
|
||||||
|
<el-button link type="primary" icon="Download" @click="handleDownload(scope.row)" v-hasPermi="['cailiaoshebei:purchaseDoc:downloadWord']"
|
||||||
|
>下载</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -379,6 +382,15 @@ const cancel = () => {
|
|||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
const handleDownload = async (row) => {
|
||||||
|
proxy?.download(
|
||||||
|
'/cailiaoshebei/purchaseDoc/export/word',
|
||||||
|
{
|
||||||
|
id: row.id
|
||||||
|
},
|
||||||
|
`${row.docCode}.doc`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleDetail = async (row?: PurchaseDocVO) => {
|
const handleDetail = async (row?: PurchaseDocVO) => {
|
||||||
proxy?.$modal.loading('加载中');
|
proxy?.$modal.loading('加载中');
|
||||||
|
@ -23,9 +23,9 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patch:master:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['patch:master:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<!-- <el-col :span="1.5">
|
||||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['patch:master:export']">导出</el-button>
|
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['patch:master:export']">导出</el-button>
|
||||||
</el-col>
|
</el-col> -->
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
@ -41,21 +41,16 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-upload ref="uploadRef" class="upload-demo" :http-request="handleImport" :show-file-list="false">
|
<el-upload ref="uploadRef" class="upload-demo" :http-request="handleImport" :show-file-list="false">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<el-button plain type="primary">导入excel</el-button>
|
<el-button plain type="primary">导入excel</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-col>
|
|
||||||
<el-col :span="1.5">
|
|
||||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['land:landBlock:remove']"
|
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<el-table draggable v-loading="loading" :data="landBlockList" @selection-change="handleSelectionChange">
|
<el-table draggable v-loading="loading" :data="landBlockList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="index" label="序号" width="55" align="center" />
|
||||||
<el-table-column label="地块编号" align="center" prop="landCode" />
|
<el-table-column label="地块编号" align="center" prop="landCode" />
|
||||||
<el-table-column label="地块名称" align="center" prop="landName" />
|
<el-table-column label="地块名称" align="center" prop="landName" />
|
||||||
<el-table-column label="方阵" align="center" prop="unit" />
|
<el-table-column label="方阵" align="center" prop="unit" />
|
||||||
@ -80,11 +75,9 @@
|
|||||||
</el-table>
|
</el-table>
|
||||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
<!-- 地块表单弹窗 -->
|
||||||
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
<el-dialog draggable :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
<el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="landBlockFormRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<!-- <el-form-item label="地块编号" prop="landCode">
|
|
||||||
<el-input v-model="form.landCode" placeholder="请输入地块编号" />
|
|
||||||
</el-form-item> -->
|
|
||||||
<el-form-item label="地块名称" prop="landName">
|
<el-form-item label="地块名称" prop="landName">
|
||||||
<el-input v-model="form.landName" placeholder="请输入地块名称" />
|
<el-input v-model="form.landName" placeholder="请输入地块名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -111,15 +104,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="800px" append-to-body>
|
<!-- 关联方阵弹窗(核心修改区域) -->
|
||||||
|
<el-dialog draggable :title="dialogMatrix.title" v-model="dialogMatrix.visible" width="900px" append-to-body>
|
||||||
<el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button>
|
<el-button type="primary" plain icon="Plus" @click="addUnitBoItem" style="margin-bottom: 15px">添加</el-button>
|
||||||
<el-form ref="landBlockFormMatrixRef" :model="formM" :rules="rules" label-width="100px">
|
<!-- 方阵表单:绑定unitBoList的索引,实现动态校验 -->
|
||||||
<el-row v-for="(item, i) of unitBoList" :key="i">
|
<el-form ref="landBlockFormMatrixRef" :model="formM" label-width="100px">
|
||||||
<el-col :span="9">
|
<el-row v-for="(item, i) of unitBoList" :key="i" class="mb-4">
|
||||||
<el-form-item label="方阵" prop="matrixId">
|
<!-- 方阵选择:必填校验 -->
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item
|
||||||
|
label="方阵"
|
||||||
|
:prop="`unitBoList[${i}].unitProjectId`"
|
||||||
|
:rules="[
|
||||||
|
{ required: true, message: '请选择方阵', trigger: 'change' },
|
||||||
|
{ type: 'array', min: 2, message: '请选择完整的方阵层级', trigger: 'change' }
|
||||||
|
]"
|
||||||
|
>
|
||||||
<el-cascader
|
<el-cascader
|
||||||
:options="fangzhenList"
|
:options="fangzhenList"
|
||||||
placeholder="请选择"
|
placeholder="请选择方阵"
|
||||||
filterable
|
filterable
|
||||||
:props="{ value: 'matrixId', label: 'name' }"
|
:props="{ value: 'matrixId', label: 'name' }"
|
||||||
v-model="item.unitProjectId"
|
v-model="item.unitProjectId"
|
||||||
@ -127,18 +130,28 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="7">
|
<!-- 所属工区:必填校验 -->
|
||||||
<el-form-item label="所属工区" prop="unitProjectArea">
|
<el-col :span="8">
|
||||||
|
<el-form-item
|
||||||
|
label="所属工区"
|
||||||
|
:prop="`unitBoList[${i}].unitProjectArea`"
|
||||||
|
:rules="{ required: true, message: '请输入所属工区', trigger: 'blur' }"
|
||||||
|
>
|
||||||
<el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" />
|
<el-input v-model="item.unitProjectArea" placeholder="请输入所属工区" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<!-- 方阵状态:必填校验 -->
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="方阵状态" prop="unitProjectStatus">
|
<el-form-item
|
||||||
|
label="方阵状态"
|
||||||
|
:prop="`unitBoList[${i}].unitProjectStatus`"
|
||||||
|
:rules="{ required: true, message: '请输入方阵状态', trigger: 'blur' }"
|
||||||
|
>
|
||||||
<el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" />
|
<el-input v-model="item.unitProjectStatus" placeholder="请输入方阵状态" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1" style="margin-left: 15px">
|
<el-col :span="1" style="margin-left: 15px; display: flex; align-items: flex-end">
|
||||||
<el-button type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
<el-button style="margin-bottom: 18px" type="danger" icon="Delete" @click="removeUnitBoItem(i)"></el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -153,44 +166,65 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="LandBlock" lang="ts">
|
<script setup name="LandBlock" lang="ts">
|
||||||
import { listLandBlock, getLandBlock, delLandBlock, LandUnit, addLandBlock, updateLandBlock, subMatrix,importLandBlock } from '@/api/system/landTransfer/landBlock';
|
import {
|
||||||
|
listLandBlock,
|
||||||
|
getLandBlock,
|
||||||
|
delLandBlock,
|
||||||
|
LandUnit,
|
||||||
|
addLandBlock,
|
||||||
|
updateLandBlock,
|
||||||
|
subMatrix,
|
||||||
|
importLandBlock
|
||||||
|
} from '@/api/system/landTransfer/landBlock';
|
||||||
import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types';
|
import { LandBlockVO, LandBlockQuery, LandBlockForm } from '@/api/system/landTransfer/landBlock/types';
|
||||||
import { useUserStoreHook } from '@/store/modules/user';
|
import { useUserStoreHook } from '@/store/modules/user';
|
||||||
|
import { getCurrentInstance, ComponentInternalInstance, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
import { ElFormInstance, ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
// 类型定义补充(避免any)
|
||||||
|
interface DialogOption {
|
||||||
|
visible: boolean;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UnitBoItem {
|
||||||
|
unitProjectArea: string;
|
||||||
|
unitProjectStatus: string;
|
||||||
|
unitProjectId: (string | number)[]; // 级联选择值(数组)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础实例与Store
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
// 获取用户 store
|
|
||||||
const userStore = useUserStoreHook();
|
const userStore = useUserStoreHook();
|
||||||
// 从 store 中获取项目列表和当前选中的项目
|
|
||||||
const currentProject = computed(() => userStore.selectedProject);
|
const currentProject = computed(() => userStore.selectedProject);
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
const landBlockList = ref<LandBlockVO[]>([]);
|
const landBlockList = ref<LandBlockVO[]>([]);
|
||||||
const fangzhenList = ref([]); //方阵列表数据
|
const fangzhenList = ref<any[]>([]); // 方阵列表(实际项目建议定义具体类型)
|
||||||
const buttonLoading = ref(false);
|
const buttonLoading = ref(false);
|
||||||
const loading = ref(true);
|
const loading = ref(true);
|
||||||
const showSearch = ref(true);
|
const showSearch = ref(true);
|
||||||
const unitBoList = ref([
|
const uploadRef = ref<any>(null); // upload组件ref
|
||||||
{
|
|
||||||
unitProjectArea: '1',
|
// 方阵表单数据(核心修改:初始值为空,避免默认填充无效数据)
|
||||||
unitProjectStatus: '1',
|
const unitBoList = ref<UnitBoItem[]>([{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }]);
|
||||||
unitProjectId: []
|
|
||||||
}
|
// 表格选择相关
|
||||||
]);
|
|
||||||
const ids = ref<Array<string | number>>([]);
|
const ids = ref<Array<string | number>>([]);
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const multiple = ref(true);
|
const multiple = ref(true);
|
||||||
const total = ref(0);
|
const total = ref(0);
|
||||||
|
|
||||||
|
// 表单Ref
|
||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const landBlockFormRef = ref<ElFormInstance>();
|
const landBlockFormRef = ref<ElFormInstance>();
|
||||||
const landBlockFormMatrixRef = ref<ElFormInstance>();
|
const landBlockFormMatrixRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
// 弹窗配置
|
||||||
visible: false,
|
const dialog = reactive<DialogOption>({ visible: false, title: '' });
|
||||||
title: ''
|
const dialogMatrix = reactive<DialogOption>({ visible: false, title: '选择方阵' });
|
||||||
});
|
|
||||||
|
|
||||||
const dialogMatrix = reactive<DialogOption>({
|
|
||||||
visible: false,
|
|
||||||
title: '选择方阵'
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// 初始表单数据
|
||||||
const initFormData: LandBlockForm = {
|
const initFormData: LandBlockForm = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
projectId: currentProject.value?.id,
|
projectId: currentProject.value?.id,
|
||||||
@ -202,11 +236,11 @@ const initFormData: LandBlockForm = {
|
|||||||
farmerCount: undefined,
|
farmerCount: undefined,
|
||||||
remark: undefined
|
remark: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 核心数据(含表单规则)
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
form: { ...initFormData },
|
form: { ...initFormData },
|
||||||
formM: {
|
formM: { landId: undefined }, // 方阵关联表单(仅存地块ID)
|
||||||
landId: undefined
|
|
||||||
},
|
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@ -219,6 +253,7 @@ const data = reactive({
|
|||||||
farmerCount: undefined,
|
farmerCount: undefined,
|
||||||
params: {}
|
params: {}
|
||||||
},
|
},
|
||||||
|
// 地块表单规则(原有规则保留)
|
||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||||
@ -229,216 +264,285 @@ const data = reactive({
|
|||||||
|
|
||||||
const { queryParams, form, rules, formM } = toRefs(data);
|
const { queryParams, form, rules, formM } = toRefs(data);
|
||||||
|
|
||||||
/** 查询地块信息列表 */
|
/** 查询地块列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await listLandBlock(queryParams.value);
|
try {
|
||||||
landBlockList.value = res.rows;
|
const res = await listLandBlock(queryParams.value);
|
||||||
total.value = res.total;
|
landBlockList.value = res.rows;
|
||||||
loading.value = false;
|
total.value = res.total;
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('获取地块列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 取消按钮 */
|
/** 地块表单取消 */
|
||||||
const cancel = () => {
|
const cancel = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 表单重置 */
|
/** 地块表单重置 */
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
form.value = { ...initFormData };
|
form.value = { ...initFormData };
|
||||||
landBlockFormRef.value?.resetFields();
|
landBlockFormRef.value?.resetFields();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索提交 */
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.value.pageNum = 1;
|
queryParams.value.pageNum = 1;
|
||||||
getList();
|
getList();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 重置按钮操作 */
|
/** 搜索重置 */
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 多选框选中数据 */
|
/** 表格选择变化 */
|
||||||
const handleSelectionChange = (selection: LandBlockVO[]) => {
|
const handleSelectionChange = (selection: LandBlockVO[]) => {
|
||||||
ids.value = selection.map((item) => item.id);
|
ids.value = selection.map((item) => item.id);
|
||||||
single.value = selection.length != 1;
|
single.value = selection.length !== 1;
|
||||||
multiple.value = !selection.length;
|
multiple.value = selection.length === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 新增按钮操作 */
|
/** 新增地块 */
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
reset();
|
reset();
|
||||||
dialog.visible = true;
|
dialog.visible = true;
|
||||||
dialog.title = '添加地块信息';
|
dialog.title = '添加地块信息';
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 修改按钮操作 */
|
/** 编辑地块 */
|
||||||
const handleUpdate = async (row?: LandBlockVO) => {
|
const handleUpdate = async (row?: LandBlockVO) => {
|
||||||
reset();
|
reset();
|
||||||
const _id = row?.id || ids.value[0];
|
const _id = row?.id || ids.value[0];
|
||||||
const res = await getLandBlock(_id);
|
if (!_id) return proxy?.$modal.msgWarning('请选择要编辑的地块');
|
||||||
Object.assign(form.value, res.data);
|
|
||||||
dialog.visible = true;
|
try {
|
||||||
dialog.title = '修改地块信息';
|
const res = await getLandBlock(_id);
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = '修改地块信息';
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('获取地块详情失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 提交按钮 */
|
/** 提交地块表单 */
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
landBlockFormRef.value?.validate(async (valid: boolean) => {
|
landBlockFormRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
buttonLoading.value = true;
|
|
||||||
|
buttonLoading.value = true;
|
||||||
|
try {
|
||||||
if (form.value.id) {
|
if (form.value.id) {
|
||||||
await updateLandBlock(form.value).finally(() => (buttonLoading.value = false));
|
await updateLandBlock(form.value);
|
||||||
} else {
|
} else {
|
||||||
await addLandBlock(form.value).finally(() => (buttonLoading.value = false));
|
await addLandBlock(form.value);
|
||||||
}
|
}
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
proxy?.$modal.msgSuccess('操作成功');
|
||||||
dialog.visible = false;
|
dialog.visible = false;
|
||||||
await getList();
|
await getList();
|
||||||
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError(form.value.id ? '修改失败' : '新增失败');
|
||||||
|
} finally {
|
||||||
|
buttonLoading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除地块 */
|
||||||
const handleDelete = async (row?: LandBlockVO) => {
|
const handleDelete = async (row?: LandBlockVO) => {
|
||||||
const _ids = row?.id || ids.value;
|
const _ids = row?.id || ids.value;
|
||||||
await proxy?.$modal.confirm('是否确认删除地块信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
if (!_ids.length) return proxy?.$modal.msgWarning('请选择要删除的地块');
|
||||||
await delLandBlock(_ids);
|
|
||||||
proxy?.$modal.msgSuccess('删除成功');
|
try {
|
||||||
await getList();
|
await proxy?.$modal.confirm(`是否确认删除地块信息编号为"${_ids}"的数据项?`);
|
||||||
|
await delLandBlock(_ids);
|
||||||
|
proxy?.$modal.msgSuccess('删除成功');
|
||||||
|
await getList();
|
||||||
|
} catch (err) {
|
||||||
|
// 取消确认时不提示错误
|
||||||
|
if (err !== 'cancel') proxy?.$modal.msgError('删除失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取方阵列表
|
/** 获取方阵列表 */
|
||||||
const getfangzhenList = async () => {
|
const getfangzhenList = async () => {
|
||||||
|
if (!currentProject.value?.id) return;
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await subMatrix(currentProject.value?.id);
|
try {
|
||||||
res.data.forEach((item) => {
|
const res = await subMatrix(currentProject.value.id);
|
||||||
item.children.forEach((item2) => {
|
// 处理方阵数据(级联选择需父子结构,此处保留原有逻辑)
|
||||||
item2.matrixId = item2.name + '_' + item2.matrixId;
|
res.data.forEach((item: any) => {
|
||||||
|
item.children?.forEach((item2: any) => {
|
||||||
|
item2.matrixId = `${item2.name}_${item2.matrixId}`; // 拼接名称+ID,便于后续拆分
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
fangzhenList.value = res.data;
|
||||||
fangzhenList.value = res.data;
|
} catch (err) {
|
||||||
|
proxy?.$modal.msgError('获取方阵列表失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleView = async (row) => {
|
/** 关联方阵(核心修改:打开弹窗前强制重置表单) */
|
||||||
// 关联方阵
|
const handleView = async (row: LandBlockVO) => {
|
||||||
|
if (!row?.id) return proxy?.$modal.msgWarning('请选择有效的地块');
|
||||||
|
|
||||||
|
// 1. 重置方阵表单(清空历史数据)
|
||||||
|
resetMatrix();
|
||||||
|
// 2. 绑定当前地块ID
|
||||||
|
formM.value.landId = row.id;
|
||||||
|
// 3. 打开弹窗
|
||||||
dialogMatrix.visible = true;
|
dialogMatrix.visible = true;
|
||||||
dialogMatrix.title = '关联方阵';
|
dialogMatrix.title = `关联方阵(地块:${row.landName || row.landCode})`;
|
||||||
data.formM.landId = row.id;
|
|
||||||
};
|
};
|
||||||
// 动态添加unitBoList项
|
|
||||||
|
/** 新增方阵表单项 */
|
||||||
const addUnitBoItem = () => {
|
const addUnitBoItem = () => {
|
||||||
unitBoList.value.push({
|
unitBoList.value.push({
|
||||||
unitProjectArea: '',
|
unitProjectArea: '',
|
||||||
unitProjectStatus: '',
|
unitProjectStatus: '',
|
||||||
unitProjectId: []
|
unitProjectId: [] // 级联选择初始为空数组
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 移除unitBoList项
|
/** 删除方阵表单项 */
|
||||||
const removeUnitBoItem = (index: number) => {
|
const removeUnitBoItem = (index: number) => {
|
||||||
if (unitBoList.value.length > 1) {
|
if (unitBoList.value.length <= 1) {
|
||||||
unitBoList.value.splice(index, 1);
|
return proxy?.$modal.msgWarning('至少保留一项方阵配置');
|
||||||
} else {
|
|
||||||
proxy?.$modal.msgWarning('至少保留一项');
|
|
||||||
}
|
}
|
||||||
|
unitBoList.value.splice(index, 1);
|
||||||
|
// 重置表单校验状态(避免删除后残留校验提示)
|
||||||
|
landBlockFormMatrixRef.value?.clearValidate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 提交方阵关联表单 */
|
||||||
const submitFormMatrix = () => {
|
const submitFormMatrix = () => {
|
||||||
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
landBlockFormMatrixRef.value?.validate(async (valid: boolean) => {
|
||||||
if (valid) {
|
if (!valid) return;
|
||||||
var arr = [];
|
if (!formM.value.landId) return proxy?.$modal.msgWarning('地块ID异常,请重新选择地块');
|
||||||
unitBoList.value.forEach((item) => {
|
|
||||||
let str = item.unitProjectId[1].split('_');
|
try {
|
||||||
arr.push({
|
// 处理方阵数据(拆分名称+ID)
|
||||||
unitProjectArea: item.unitProjectArea,
|
const unitBoListParams = unitBoList.value.map((item) => {
|
||||||
unitProjectStatus: item.unitProjectStatus,
|
const [unitProjectName, unitProjectId] = item.unitProjectId[1]?.split('_') || [];
|
||||||
unitProjectId: str[1],
|
if (!unitProjectId) throw new Error('方阵ID解析失败,请重新选择方阵');
|
||||||
unitProjectName: str[0]
|
|
||||||
});
|
return {
|
||||||
|
unitProjectArea: item.unitProjectArea.trim(),
|
||||||
|
unitProjectStatus: item.unitProjectStatus.trim(),
|
||||||
|
unitProjectId: unitProjectId, // 纯ID(后端需要)
|
||||||
|
unitProjectName: unitProjectName // 名称(可选,用于显示)
|
||||||
|
};
|
||||||
});
|
});
|
||||||
var res = await LandUnit({ ...formM.value, unitBoList: arr });
|
|
||||||
if (res.code == 200) {
|
// 调用关联接口
|
||||||
proxy?.$modal.msgSuccess('操作成功');
|
const res = await LandUnit({
|
||||||
|
landId: formM.value.landId,
|
||||||
|
unitBoList: unitBoListParams
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
proxy?.$modal.msgSuccess('关联方阵成功');
|
||||||
dialogMatrix.visible = false;
|
dialogMatrix.visible = false;
|
||||||
await getList();
|
await getList(); // 刷新地块列表
|
||||||
} else {
|
} else {
|
||||||
proxy?.$modal.msgError(res.msg);
|
proxy?.$modal.msgError(res.msg || '关联失败');
|
||||||
}
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
proxy?.$modal.msgError(err.msg || '关联过程异常');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 取消按钮 */
|
|
||||||
|
/** 方阵表单取消 */
|
||||||
const cancelMatrix = () => {
|
const cancelMatrix = () => {
|
||||||
resetMatrix();
|
resetMatrix();
|
||||||
dialogMatrix.visible = false;
|
dialogMatrix.visible = false;
|
||||||
};
|
};
|
||||||
/** 表单重置 */
|
|
||||||
|
/** 方阵表单重置(核心修改:清空所有数据+重置校验) */
|
||||||
const resetMatrix = () => {
|
const resetMatrix = () => {
|
||||||
data.formM.landId = '';
|
// 1. 清空地块ID
|
||||||
unitBoList.value = [
|
formM.value.landId = undefined;
|
||||||
{
|
// 2. 重置方阵列表(仅保留一个空项)
|
||||||
unitProjectArea: '1',
|
unitBoList.value = [{ unitProjectArea: '', unitProjectStatus: '', unitProjectId: [] }];
|
||||||
unitProjectStatus: '1',
|
// 3. 重置表单校验状态
|
||||||
unitProjectId: []
|
if (landBlockFormMatrixRef.value) {
|
||||||
}
|
landBlockFormMatrixRef.value.resetFields();
|
||||||
];
|
landBlockFormMatrixRef.value.clearValidate();
|
||||||
landBlockFormMatrixRef.value?.resetFields();
|
}
|
||||||
};
|
};
|
||||||
//监听项目id刷新数据
|
|
||||||
|
/** 监听项目变化,刷新数据 */
|
||||||
const listeningProject = watch(
|
const listeningProject = watch(
|
||||||
() => currentProject.value?.id,
|
() => currentProject.value?.id,
|
||||||
(nid, oid) => {
|
(newId) => {
|
||||||
queryParams.value.projectId = nid;
|
if (newId) {
|
||||||
getfangzhenList();
|
queryParams.value.projectId = newId;
|
||||||
getList();
|
getfangzhenList(); // 刷新方阵列表
|
||||||
}
|
getList(); // 刷新地块列表
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true } // 初始加载时执行一次
|
||||||
);
|
);
|
||||||
|
|
||||||
// 导入文件
|
/** 导入Excel */
|
||||||
const handleImport = (options:any) => {
|
const handleImport = (options: { file: File }) => {
|
||||||
|
if (!currentProject.value?.id) return proxy?.$modal.msgWarning('请先选择项目');
|
||||||
|
if (!options.file) return proxy?.$modal.msgWarning('请选择Excel文件');
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
let formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', options.file);
|
formData.append('file', options.file);
|
||||||
importLandBlock(currentProject.value?.id,formData).then((res) => {
|
|
||||||
if (res.code == 200) {
|
importLandBlock(currentProject.value.id, formData)
|
||||||
proxy.$modal.msgSuccess(res.msg || '导入成功');
|
.then((res) => {
|
||||||
getList();
|
if (res.code === 200) {
|
||||||
getfangzhenList();
|
proxy?.$modal.msgSuccess(res.msg || '导入成功');
|
||||||
}
|
getList();
|
||||||
}).catch((err) => {
|
getfangzhenList();
|
||||||
proxy.$modal.msgError(err.msg || '导入失败');
|
} else {
|
||||||
}).finally(() => {
|
proxy?.$modal.msgError(res.msg || '导入失败');
|
||||||
loading.value = false;
|
}
|
||||||
});
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
proxy?.$modal.msgError(err.msg || '导入接口异常');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 下载模板
|
/** 下载导入模板 */
|
||||||
const downloadTemplate = () => {
|
const downloadTemplate = () => {
|
||||||
// 导出模版文件
|
|
||||||
try {
|
try {
|
||||||
// 创建a标签
|
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
// 设置PDF文件路径 - 相对于public目录
|
link.href = '/landBlock.xlsx'; // 模板路径(需确保public目录下存在该文件)
|
||||||
link.href = '/landBlock.xlsx';
|
link.download = '地块信息导入模板.xlsx'; // 下载后文件名
|
||||||
// 设置下载后的文件名
|
|
||||||
link.download = '地块信息导入模板.xlsx';
|
|
||||||
// 触发点击
|
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click(); // 触发下载
|
||||||
// 清理
|
} catch (err) {
|
||||||
document.body.removeChild(link);
|
proxy?.$modal.msgError('模板下载失败,请重试');
|
||||||
} catch (error) {
|
} finally {
|
||||||
alert('下载失败,请重试');
|
document.body.removeChild(link); // 清理DOM
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 生命周期:组件卸载时清理监听 */
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
listeningProject();
|
listeningProject();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 生命周期:组件挂载时初始化数据 */
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList();
|
getList();
|
||||||
getfangzhenList();
|
getfangzhenList();
|
||||||
|
@ -31,14 +31,21 @@
|
|||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landTransferLedger:add']">新增</el-button>
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['land:landTransferLedger:add']">新增</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="6"></el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-tag size="large" type="primary">设计面积:{{ detailInfo.designArea }}亩</el-tag>
|
<el-tag size="large" type="primary"
|
||||||
|
><span style="font-size: 20px">设计面积:{{ detailInfo.designArea }} 亩</span></el-tag
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-tag size="large" type="success">已流转面积:{{ detailInfo.transferAea }}亩</el-tag>
|
<el-tag size="large" type="success"
|
||||||
|
><span style="font-size: 20px">已流转面积:{{ detailInfo.transferAea }} 亩</span></el-tag
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-tag size="large" type="warning">租金:{{ detailInfo.landRent / 1000 }}万元</el-tag>
|
<el-tag size="large" type="warning"
|
||||||
|
><span style="font-size: 20px">租金:{{ detailInfo.landRent / 1000 }} 万元</span></el-tag
|
||||||
|
>
|
||||||
</el-col>
|
</el-col>
|
||||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -123,7 +130,7 @@
|
|||||||
></el-col>
|
></el-col>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12"
|
<el-col v-if="form.transferStatus == '1'" :span="12"
|
||||||
><el-form-item label="流转比例(%)" prop="transferRatio">
|
><el-form-item label="流转比例(%)" prop="transferRatio">
|
||||||
<el-input v-model="form.transferRatio" type="number" placeholder="请输入流转比例" /> </el-form-item
|
<el-input v-model="form.transferRatio" type="number" max="100" min="0" placeholder="请输入流转比例" /> </el-form-item
|
||||||
></el-col>
|
></el-col>
|
||||||
<el-col v-if="form.transferStatus == '1'" :span="12">
|
<el-col v-if="form.transferStatus == '1'" :span="12">
|
||||||
<el-form-item label="土地租金(元)" prop="landRent">
|
<el-form-item label="土地租金(元)" prop="landRent">
|
||||||
@ -264,7 +271,21 @@ const data = reactive<PageData<LandTransferLedgerForm, LandTransferLedgerQuery>>
|
|||||||
rules: {
|
rules: {
|
||||||
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
|
||||||
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
projectId: [{ required: true, message: '项目ID不能为空', trigger: 'blur' }],
|
||||||
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }]
|
landType: [{ required: true, message: '土地类型不能为空', trigger: 'change' }],
|
||||||
|
transferRatio: [
|
||||||
|
{ required: true, message: '流转比例不能为空', trigger: ['blur', 'change'] }, // 必填
|
||||||
|
{
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
// 校验数值是否在 0-100 之间(包含0和100)
|
||||||
|
if (value < 0 || value > 100) {
|
||||||
|
callback(new Error('流转比例必须在 0-100 之间'));
|
||||||
|
} else {
|
||||||
|
callback(); // 校验通过
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'blur' // 失去焦点时触发校验
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const detailInfo = ref({
|
const detailInfo = ref({
|
||||||
|
Reference in New Issue
Block a user