This commit is contained in:
吴红兵
2026-03-07 12:35:45 +08:00
parent 271710e870
commit b997b3ba48
423 changed files with 79612 additions and 91574 deletions

View File

@@ -1,356 +1,351 @@
<template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px">
<el-row :gutter="24">
<el-col :span="8" class="mb20">
<el-form-item label="项目名称">
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" disabled />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="需求部门">
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" disabled/>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="是否签订合同" prop="hasContract">
<el-radio-group v-model="form.hasContract">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20" v-if="form.hasContract === '1'">
<el-form-item label="合同" prop="contractId">
<el-select
v-model="form.contractId"
placeholder="请选择合同"
clearable
filterable
style="width: 100%"
:loading="contractLoading"
@visible-change="onContractSelectVisibleChange"
>
<el-option
v-for="item in contractOptions"
:key="item.id"
:label="item.contractName || item.contractNo || item.id"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="是否分期验收" prop="isInstallment">
<el-radio-group v-model="form.isInstallment">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20" v-if="form.isInstallment === '1'">
<el-form-item label="分期次数" prop="totalPhases">
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="供应商名称" prop="supplierName">
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="资产管理员" prop="assetAdminId">
<el-select
v-model="form.assetAdminId"
placeholder="请输入姓名或工号搜索"
filterable
remote
clearable
reserve-keyword
:remote-method="searchAssetAdmin"
:loading="assetAdminLoading"
style="width: 100%"
@change="onAssetAdminChange"
>
<el-option
v-for="item in assetAdminOptions"
:key="item.teacherNo"
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
:value="item.teacherNo"
>
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
</el-option>
</el-select>
<div class="field-note">如入固定资产必填</div>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="采购人员" prop="purchaserId">
<el-select
v-model="form.purchaserId"
placeholder="请输入姓名或工号搜索"
filterable
remote
clearable
reserve-keyword
:remote-method="searchPurchaser"
:loading="purchaserLoading"
style="width: 100%"
@change="onPurchaserChange"
>
<el-option
v-for="item in purchaserOptions"
:key="item.teacherNo"
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
:value="item.teacherNo"
>
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-form ref="formRef" :model="form" :rules="rules" label-width="140px">
<el-row :gutter="24">
<el-col :span="8" class="mb20">
<el-form-item label="项目名称">
<el-input :model-value="projectName || form.projectName" readonly placeholder="-" disabled />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="需求部门">
<el-input :model-value="deptName || form.deptName" readonly placeholder="-" disabled />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="是否签订合同" prop="hasContract">
<el-radio-group v-model="form.hasContract">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20" v-if="form.hasContract === '1'">
<el-form-item label="合同" prop="contractId">
<el-select
v-model="form.contractId"
placeholder="请选择合同"
clearable
filterable
style="width: 100%"
:loading="contractLoading"
@visible-change="onContractSelectVisibleChange"
>
<el-option v-for="item in contractOptions" :key="item.id" :label="item.contractName || item.contractNo || item.id" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="是否分期验收" prop="isInstallment">
<el-radio-group v-model="form.isInstallment">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20" v-if="form.isInstallment === '1'">
<el-form-item label="分期次数" prop="totalPhases">
<el-input-number v-model="form.totalPhases" :min="1" :max="99" placeholder="请输入" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="供应商名称" prop="supplierName">
<el-input v-model="form.supplierName" placeholder="选择合同后自动带出" clearable />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="资产管理员" prop="assetAdminId">
<el-select
v-model="form.assetAdminId"
placeholder="请输入姓名或工号搜索"
filterable
remote
clearable
reserve-keyword
:remote-method="searchAssetAdmin"
:loading="assetAdminLoading"
style="width: 100%"
@change="onAssetAdminChange"
>
<el-option
v-for="item in assetAdminOptions"
:key="item.teacherNo"
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
:value="item.teacherNo"
>
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
</el-option>
</el-select>
<div class="field-note">如入固定资产必填</div>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="采购人员" prop="purchaserId">
<el-select
v-model="form.purchaserId"
placeholder="请输入姓名或工号搜索"
filterable
remote
clearable
reserve-keyword
:remote-method="searchPurchaser"
:loading="purchaserLoading"
style="width: 100%"
@change="onPurchaserChange"
>
<el-option
v-for="item in purchaserOptions"
:key="item.teacherNo"
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
:value="item.teacherNo"
>
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
<span style="color: #999; font-size: 12px; margin-left: 8px">{{ item.teacherNo }}</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20" v-if="form.hasContract === '0'">
<el-form-item label="成交金额" prop="transactionAmount" :required="form.hasContract === '0'">
<el-input-number
v-model="form.transactionAmount"
:min="0"
:precision="2"
placeholder="请输入成交金额"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-col :span="8" class="mb20" v-if="form.hasContract === '0'">
<el-form-item label="成交金额" prop="transactionAmount" :required="form.hasContract === '0'">
<el-input-number v-model="form.transactionAmount" :min="0" :precision="2" placeholder="请输入成交金额" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script setup lang="ts">
import { ref, reactive, watch, onMounted } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { getContracts, searchTeachers } from '/@/api/purchase/purchasingrequisition'
import { ref, reactive, watch, onMounted } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';
import { getContracts, searchTeachers } from '/@/api/purchase/purchasingrequisition';
const props = defineProps<{
modelValue: Record<string, any>
projectName?: string
deptName?: string
/** 采购申请ID用于拉取合同列表 */
purchaseId?: string | number
/** 每次打开弹窗时变化,用于强制重置内部 form */
resetKey?: number
}>()
modelValue: Record<string, any>;
projectName?: string;
deptName?: string;
/** 采购申请ID用于拉取合同列表 */
purchaseId?: string | number;
/** 每次打开弹窗时变化,用于强制重置内部 form */
resetKey?: number;
}>();
const emit = defineEmits(['update:modelValue'])
const emit = defineEmits(['update:modelValue']);
const formRef = ref<FormInstance>()
const contractOptions = ref<any[]>([])
const contractLoading = ref(false)
const contractLoaded = ref(false)
const formRef = ref<FormInstance>();
const contractOptions = ref<any[]>([]);
const contractLoading = ref(false);
const contractLoaded = ref(false);
// 采购人员相关
const purchaserOptions = ref<any[]>([])
const purchaserLoading = ref(false)
const purchaserOptions = ref<any[]>([]);
const purchaserLoading = ref(false);
// 资产管理员相关
const assetAdminOptions = ref<any[]>([])
const assetAdminLoading = ref(false)
const assetAdminOptions = ref<any[]>([]);
const assetAdminLoading = ref(false);
const form = reactive({
hasContract: '0',
contractId: '',
isInstallment: '0',
totalPhases: 1,
projectName: '',
deptName: '',
supplierName: '',
purchaserId: '',
purchaserName: '',
assetAdminId: '',
assetAdminName: '',
transactionAmount: null,
...props.modelValue,
})
hasContract: '0',
contractId: '',
isInstallment: '0',
totalPhases: 1,
projectName: '',
deptName: '',
supplierName: '',
purchaserId: '',
purchaserName: '',
assetAdminId: '',
assetAdminName: '',
transactionAmount: null,
...props.modelValue,
});
const syncFormFromModel = (val: Record<string, any> | undefined) => {
Object.assign(form, val || {})
// 加载已选人员信息用于回显
if (form.purchaserId && form.purchaserName) {
purchaserOptions.value = [{ teacherNo: form.purchaserId, realName: form.purchaserName, name: form.purchaserName }]
}
if (form.assetAdminId && form.assetAdminName) {
assetAdminOptions.value = [{ teacherNo: form.assetAdminId, realName: form.assetAdminName, name: form.assetAdminName }]
}
}
Object.assign(form, val || {});
// 加载已选人员信息用于回显
if (form.purchaserId && form.purchaserName) {
purchaserOptions.value = [{ teacherNo: form.purchaserId, realName: form.purchaserName, name: form.purchaserName }];
}
if (form.assetAdminId && form.assetAdminName) {
assetAdminOptions.value = [{ teacherNo: form.assetAdminId, realName: form.assetAdminName, name: form.assetAdminName }];
}
};
const loadContractOptions = async () => {
if (contractLoaded.value || contractLoading.value) return
if (form.hasContract !== '1') return
contractLoading.value = true
try {
const res = await getContracts(props.purchaseId ? { id: props.purchaseId } : {})
const list = res?.data
contractOptions.value = Array.isArray(list) ? list : []
contractLoaded.value = true
// 回显时:列表中含当前合同,用其供应商名称填充(若尚未有值)
if (form.contractId) {
const c = contractOptions.value.find((it: any) => it.id === form.contractId)
if (c?.supplierName) form.supplierName = c.supplierName
}
} catch (_) {
contractOptions.value = []
} finally {
contractLoading.value = false
}
}
if (contractLoaded.value || contractLoading.value) return;
if (form.hasContract !== '1') return;
contractLoading.value = true;
try {
const res = await getContracts(props.purchaseId ? { id: props.purchaseId } : {});
const list = res?.data;
contractOptions.value = Array.isArray(list) ? list : [];
contractLoaded.value = true;
// 回显时:列表中含当前合同,用其供应商名称填充(若尚未有值)
if (form.contractId) {
const c = contractOptions.value.find((it: any) => it.id === form.contractId);
if (c?.supplierName) form.supplierName = c.supplierName;
}
} catch (_) {
contractOptions.value = [];
} finally {
contractLoading.value = false;
}
};
const onContractSelectVisibleChange = (visible: boolean) => {
if (visible && form.hasContract === '1' && contractOptions.value.length === 0) {
loadContractOptions()
}
}
if (visible && form.hasContract === '1' && contractOptions.value.length === 0) {
loadContractOptions();
}
};
const searchPurchaser = async (query: string) => {
if (!query) {
purchaserOptions.value = []
return
}
purchaserLoading.value = true
try {
const res = await searchTeachers(query)
purchaserOptions.value = res?.data || []
} catch (_) {
purchaserOptions.value = []
} finally {
purchaserLoading.value = false
}
}
if (!query) {
purchaserOptions.value = [];
return;
}
purchaserLoading.value = true;
try {
const res = await searchTeachers(query);
purchaserOptions.value = res?.data || [];
} catch (_) {
purchaserOptions.value = [];
} finally {
purchaserLoading.value = false;
}
};
const searchAssetAdmin = async (query: string) => {
if (!query) {
assetAdminOptions.value = []
return
}
assetAdminLoading.value = true
try {
const res = await searchTeachers(query)
assetAdminOptions.value = res?.data || []
} catch (_) {
assetAdminOptions.value = []
} finally {
assetAdminLoading.value = false
}
}
if (!query) {
assetAdminOptions.value = [];
return;
}
assetAdminLoading.value = true;
try {
const res = await searchTeachers(query);
assetAdminOptions.value = res?.data || [];
} catch (_) {
assetAdminOptions.value = [];
} finally {
assetAdminLoading.value = false;
}
};
const onPurchaserChange = (teacherNo: string) => {
if (!teacherNo) {
form.purchaserId = ''
form.purchaserName = ''
return
}
const selected = purchaserOptions.value.find((item: any) => item.teacherNo === teacherNo)
if (selected) {
form.purchaserId = selected.teacherNo
form.purchaserName = selected.realName || selected.name
}
}
if (!teacherNo) {
form.purchaserId = '';
form.purchaserName = '';
return;
}
const selected = purchaserOptions.value.find((item: any) => item.teacherNo === teacherNo);
if (selected) {
form.purchaserId = selected.teacherNo;
form.purchaserName = selected.realName || selected.name;
}
};
const onAssetAdminChange = (teacherNo: string) => {
if (!teacherNo) {
form.assetAdminId = ''
form.assetAdminName = ''
return
}
const selected = assetAdminOptions.value.find((item: any) => item.teacherNo === teacherNo)
if (selected) {
form.assetAdminId = selected.teacherNo
form.assetAdminName = selected.realName || selected.name
}
}
if (!teacherNo) {
form.assetAdminId = '';
form.assetAdminName = '';
return;
}
const selected = assetAdminOptions.value.find((item: any) => item.teacherNo === teacherNo);
if (selected) {
form.assetAdminId = selected.teacherNo;
form.assetAdminName = selected.realName || selected.name;
}
};
watch(
() => props.modelValue,
(val) => {
syncFormFromModel(val)
// 回显已有合同ID时主动加载合同列表以便下拉显示合同名称后端已排除"其他申请"的合同,当前申请合同会在列表中)
if (form.hasContract === '1' && form.contractId && props.purchaseId && !contractLoaded.value && !contractLoading.value) {
loadContractOptions()
}
},
{ deep: true, immediate: true }
)
() => props.modelValue,
(val) => {
syncFormFromModel(val);
// 回显已有合同ID时主动加载合同列表以便下拉显示合同名称后端已排除"其他申请"的合同,当前申请合同会在列表中)
if (form.hasContract === '1' && form.contractId && props.purchaseId && !contractLoaded.value && !contractLoading.value) {
loadContractOptions();
}
},
{ deep: true, immediate: true }
);
// resetKey 变化时强制用 modelValue 覆盖内部 form并重置合同列表以便重新拉取
watch(() => props.resetKey, () => {
syncFormFromModel(props.modelValue)
contractLoaded.value = false
contractOptions.value = []
})
watch(form, () => emit('update:modelValue', { ...form }), { deep: true })
watch(
() => props.resetKey,
() => {
syncFormFromModel(props.modelValue);
contractLoaded.value = false;
contractOptions.value = [];
}
);
watch(form, () => emit('update:modelValue', { ...form }), { deep: true });
watch(() => form.hasContract, (val) => {
if (val === '1') {
contractLoaded.value = false
loadContractOptions()
} else {
contractOptions.value = []
contractLoaded.value = false
}
// hasContract 变化时触发 transactionAmount 校验
formRef.value?.validateField('transactionAmount')
})
watch(
() => form.hasContract,
(val) => {
if (val === '1') {
contractLoaded.value = false;
loadContractOptions();
} else {
contractOptions.value = [];
contractLoaded.value = false;
}
// hasContract 变化时触发 transactionAmount 校验
formRef.value?.validateField('transactionAmount');
}
);
// 选择合同后,自动带出合同供应商名称
watch(
() => form.contractId,
(val) => {
if (!val) {
form.supplierName = ''
return
}
const c = contractOptions.value.find((it: any) => it.id === val)
if (c && c.supplierName) {
form.supplierName = c.supplierName
}
}
)
() => form.contractId,
(val) => {
if (!val) {
form.supplierName = '';
return;
}
const c = contractOptions.value.find((it: any) => it.id === val);
if (c && c.supplierName) {
form.supplierName = c.supplierName;
}
}
);
onMounted(() => {
if (form.hasContract === '1') {
loadContractOptions()
}
})
if (form.hasContract === '1') {
loadContractOptions();
}
});
const rules: FormRules = {
hasContract: [{ required: true, message: '请选择是否签订合同', trigger: 'change' }],
isInstallment: [{ required: true, message: '请选择是否分期验收', trigger: 'change' }],
totalPhases: [{ required: true, message: '请输入分期次数', trigger: 'blur' }],
transactionAmount: [
{
validator: (rule: any, value: any, callback: any) => {
// 未签订合同时,成交金额为必填
if (form.hasContract === '0' && (value === null || value === undefined || value === '')) {
callback(new Error('未签订合同时,成交金额为必填'))
} else {
callback()
}
},
trigger: 'blur',
},
],
}
hasContract: [{ required: true, message: '请选择是否签订合同', trigger: 'change' }],
isInstallment: [{ required: true, message: '请选择是否分期验收', trigger: 'change' }],
totalPhases: [{ required: true, message: '请输入分期次数', trigger: 'blur' }],
transactionAmount: [
{
validator: (rule: any, value: any, callback: any) => {
// 未签订合同时,成交金额为必填
if (form.hasContract === '0' && (value === null || value === undefined || value === '')) {
callback(new Error('未签订合同时,成交金额为必填'));
} else {
callback();
}
},
trigger: 'blur',
},
],
};
const validate = () => formRef.value?.validate()
const validate = () => formRef.value?.validate();
defineExpose({ validate, form })
defineExpose({ validate, form });
</script>
<style scoped>
.mb20 {
margin-bottom: 20px;
margin-bottom: 20px;
}
.field-note {
font-size: 12px;
color: #999;
margin-top: 4px;
font-size: 12px;
color: #999;
margin-top: 4px;
}
</style>