0509新功能优化

This commit is contained in:
lzm
2026-05-08 17:38:50 +08:00
parent 9ea02751de
commit 92c5071fab
18 changed files with 695 additions and 345 deletions

View File

@@ -5,250 +5,264 @@
v-loading="formLoading"
:model="formData"
:rules="formRules"
label-width="120px"
label-width="130px"
>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="工程名称" prop="projectName">
<el-input v-model="formData.projectName" maxlength="200" placeholder="请输入工程名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否签订合同" prop="contractSignedFlag">
<el-switch
v-model="formData.contractSignedFlag"
active-text="已签订"
inactive-text="未签订"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="合同金额(元)" prop="contractAmount">
<el-input-number
v-model="formData.contractAmount"
:min="0"
:precision="2"
:step="1000"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工程总面积(㎡)" prop="totalConstructionArea">
<el-input-number
v-model="formData.totalConstructionArea"
:min="0"
:precision="2"
:step="100"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="建设单位" prop="constructionUnitName">
<el-input
v-model="formData.constructionUnitName"
maxlength="200"
placeholder="请输入建设单位"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工程类型" prop="projectType">
<el-select v-model="formData.projectType" class="!w-1/1" clearable placeholder="请选择">
<el-option
v-for="item in PROJECT_TYPE_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
<div class="form-section">
<div class="form-section-title">项目基础信息</div>
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="项目名称" prop="projectName">
<el-input v-model="formData.projectName" maxlength="200" placeholder="请输入项目名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工程总面积(㎡)" prop="totalConstructionArea">
<el-input-number
v-model="formData.totalConstructionArea"
:min="0"
:precision="2"
:step="100"
class="!w-1/1"
controls-position="right"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工程类别" prop="projectCategory">
<el-select
v-model="formData.projectCategory"
class="!w-1/1"
clearable
placeholder="请选择"
>
<el-option
v-for="item in PROJECT_CATEGORY_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="建设单位" prop="constructionUnitName">
<el-input
v-model="formData.constructionUnitName"
maxlength="200"
placeholder="请输入建设单位"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="联系人" prop="contactName">
<el-input v-model="formData.contactName" maxlength="64" placeholder="请输入联系人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="formData.contactPhone" maxlength="32" placeholder="请输入联系电话" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="合同签订日期" prop="contractSigningDate">
<el-date-picker
v-model="formData.contractSigningDate"
class="!w-1/1"
placeholder="请选择日期"
type="date"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目开始年度" prop="projectStartYear">
<el-date-picker
v-model="projectStartYearValue"
class="!w-1/1"
placeholder="请选择年度"
type="year"
value-format="YYYY"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="项目状态" prop="projectStatus">
<el-select
v-model="formData.projectStatus"
class="!w-1/1"
clearable
placeholder="请选择项目状态"
>
<el-option
v-for="item in PROJECT_STATUS_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="statusReasonLabel" :prop="statusReasonProp">
<el-input
v-if="formData.projectStatus === '暂停'"
v-model="formData.pauseReason"
maxlength="255"
placeholder="请输入暂停原因"
/>
<el-input
v-else-if="formData.projectStatus === '中止'"
v-model="formData.terminateReason"
maxlength="255"
placeholder="请输入中止原因"
/>
<el-input v-else disabled placeholder="进行中或完成状态无需填写原因" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="项目经理">
<div class="person-group">
<div
v-for="(item, index) in projectManagerPersons"
:key="`manager-${index}`"
class="person-row"
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工程类型" prop="projectType">
<el-select v-model="formData.projectType" class="!w-1/1" clearable placeholder="请选择">
<el-option
v-for="item in PROJECT_TYPE_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工程类别" prop="projectCategory">
<el-select
v-model="formData.projectCategory"
class="!w-1/1"
clearable
placeholder="请选择"
>
<el-select
:model-value="item.employeeId"
class="!w-1/1"
clearable
filterable
remote
reserve-keyword
placeholder="请输入项目经理姓名搜索"
:remote-method="searchEmployees"
:loading="employeeLoading"
@change="(value) => handleEmployeeChange(item, value)"
<el-option
v-for="item in PROJECT_CATEGORY_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="form-section-title">合同与财务信息</div>
<el-row :gutter="16">
<el-col :span="24">
<el-form-item label="合同状态" prop="contractSignedFlag" required>
<el-radio-group v-model="formData.contractSignedFlag">
<el-radio :value="true">已签订</el-radio>
<el-radio :value="false">未签订</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同产值(元)" prop="contractAmount">
<el-input-number
v-model="formData.contractAmount"
:min="0"
:precision="2"
:step="1000"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="签订日期" prop="contractSigningDate">
<el-date-picker
v-model="formData.contractSigningDate"
class="!w-1/1"
placeholder="请选择日期"
type="date"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="form-section-title">状态与进度</div>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="项目状态" prop="projectStatus">
<el-select
v-model="formData.projectStatus"
class="!w-1/1"
clearable
placeholder="请选择项目状态"
>
<el-option
v-for="item in PROJECT_STATUS_OPTIONS"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开始年度" prop="projectStartYear">
<el-date-picker
v-model="projectStartYearValue"
class="!w-1/1"
placeholder="请选择年度"
type="year"
value-format="YYYY"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="statusReasonLabel" :prop="statusReasonProp">
<el-input
v-if="formData.projectStatus === '暂停'"
v-model="formData.pauseReason"
maxlength="255"
placeholder="请输入暂停原因"
/>
<el-input
v-else-if="formData.projectStatus === '中止'"
v-model="formData.terminateReason"
maxlength="255"
placeholder="请输入中止原因"
/>
<el-input v-else disabled placeholder="进行中或完成状态无需填写原因" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序" prop="sortNo">
<el-input-number
v-model="formData.sortNo"
:min="0"
:precision="0"
:step="1"
class="!w-1/1"
controls-position="right"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="form-section-title">人员与建设单位联系信息</div>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="建设单位联系人" prop="contactName">
<el-input v-model="formData.contactName" maxlength="64" placeholder="请输入建设单位联系人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="建设单位联系电话" prop="contactPhone">
<el-input v-model="formData.contactPhone" maxlength="32" placeholder="请输入建设单位联系电话" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目经理">
<div class="person-group">
<div
v-for="(item, index) in projectManagerPersons"
:key="`manager-${index}`"
class="person-row"
>
<el-option
v-for="employee in employeeOptions"
:key="employee.id"
:label="employee.officeName ? `${employee.employeeName} / ${employee.officeName}` : employee.employeeName"
:value="employee.id"
/>
</el-select>
<el-button text type="danger" @click="removeRolePerson(ROLE_PROJECT_MANAGER, index)">
删除
<el-select
:model-value="item.employeeId"
class="!w-1/1"
clearable
filterable
remote
reserve-keyword
placeholder="请输入项目经理姓名搜索"
:remote-method="searchEmployees"
:loading="employeeLoading"
@change="(value) => handleEmployeeChange(item, value)"
>
<el-option
v-for="employee in employeeOptions"
:key="employee.id"
:label="employee.officeName ? `${employee.employeeName} / ${employee.officeName}` : employee.employeeName"
:value="employee.id"
/>
</el-select>
<el-button text type="danger" @click="removeRolePerson(ROLE_PROJECT_MANAGER, index)">
删除
</el-button>
</div>
<el-button text type="primary" @click="addRolePerson(ROLE_PROJECT_MANAGER)">
<Icon class="mr-5px" icon="ep:plus" />
添加项目经理
</el-button>
</div>
<el-button text type="primary" @click="addRolePerson(ROLE_PROJECT_MANAGER)">
<Icon class="mr-5px" icon="ep:plus" />
添加项目经理
</el-button>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目负责人">
<div class="person-group">
<div
v-for="(item, index) in engineeringPrincipalPersons"
:key="`principal-${index}`"
class="person-row"
>
<el-select
:model-value="item.employeeId"
class="!w-1/1"
clearable
filterable
remote
reserve-keyword
placeholder="请输入项目负责人姓名搜索"
:remote-method="searchEmployees"
:loading="employeeLoading"
@change="(value) => handleEmployeeChange(item, value)"
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工程负责人">
<div class="person-group">
<div
v-for="(item, index) in engineeringPrincipalPersons"
:key="`principal-${index}`"
class="person-row"
>
<el-option
v-for="employee in employeeOptions"
:key="employee.id"
:label="employee.officeName ? `${employee.employeeName} / ${employee.officeName}` : employee.employeeName"
:value="employee.id"
/>
</el-select>
<el-button
text
type="danger"
@click="removeRolePerson(ROLE_ENGINEERING_PRINCIPAL, index)"
>
删除
<el-select
:model-value="item.employeeId"
class="!w-1/1"
clearable
filterable
remote
reserve-keyword
placeholder="请输入工程负责人姓名搜索"
:remote-method="searchEmployees"
:loading="employeeLoading"
@change="(value) => handleEmployeeChange(item, value)"
>
<el-option
v-for="employee in employeeOptions"
:key="employee.id"
:label="employee.officeName ? `${employee.employeeName} / ${employee.officeName}` : employee.employeeName"
:value="employee.id"
/>
</el-select>
<el-button
text
type="danger"
@click="removeRolePerson(ROLE_ENGINEERING_PRINCIPAL, index)"
>
删除
</el-button>
</div>
<el-button text type="primary" @click="addRolePerson(ROLE_ENGINEERING_PRINCIPAL)">
<Icon class="mr-5px" icon="ep:plus" />
添加工程负责人
</el-button>
</div>
<el-button text type="primary" @click="addRolePerson(ROLE_ENGINEERING_PRINCIPAL)">
<Icon class="mr-5px" icon="ep:plus" />
添加项目负责人
</el-button>
</div>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
<template #footer>
@@ -315,6 +329,7 @@ const createRolePerson = (
const createFormData = (): ProjectApi.ProjectVO => ({
projectName: '',
sortNo: 0,
contractSignedFlag: true,
contractAmount: undefined,
totalConstructionArea: undefined,
@@ -443,8 +458,8 @@ watch(
)
const formRules = reactive<FormRules>({
projectName: [{ required: true, message: '工程名称不能为空', trigger: 'blur' }],
contractAmount: [{ required: true, message: '合同金额不能为空', trigger: 'blur' }],
projectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
contractAmount: [{ required: true, message: '合同产值不能为空', trigger: 'blur' }],
totalConstructionArea: [{ required: true, message: '工程总面积不能为空', trigger: 'blur' }],
projectStartYear: [{ required: true, message: '项目开始年度不能为空', trigger: 'change' }],
projectStatus: [{ required: true, message: '项目状态不能为空', trigger: 'change' }],
@@ -497,6 +512,7 @@ const emit = defineEmits(['success'])
const buildSavePayload = (): ProjectApi.ProjectSaveVO => ({
id: formData.value.id,
projectName: formData.value.projectName,
sortNo: formData.value.sortNo ?? 0,
contractSignedFlag: formData.value.contractSignedFlag,
contractAmount: formData.value.contractAmount,
totalConstructionArea: formData.value.totalConstructionArea,
@@ -556,6 +572,22 @@ const resetForm = () => {
</script>
<style lang="scss" scoped>
.form-section {
margin-bottom: 10px;
}
.form-section:last-child {
margin-bottom: 0;
}
.form-section-title {
margin-bottom: 12px;
font-size: 15px;
font-weight: 600;
line-height: 22px;
color: var(--el-text-color-primary);
}
.person-group {
display: flex;
flex-direction: column;