diff --git a/src/api/oa/erp/contractInfo/index.ts b/src/api/oa/erp/contractInfo/index.ts index 81bcf5b..b4bb36e 100644 --- a/src/api/oa/erp/contractInfo/index.ts +++ b/src/api/oa/erp/contractInfo/index.ts @@ -16,6 +16,19 @@ export const listContractInfo = (query?: ContractInfoQuery): AxiosPromise => { + return request({ + url: '/oa/erp/contractInfo/framework/list', + method: 'get', + params: query + }); +}; + /** * 查询合同信息详细 * @param contractId diff --git a/src/api/oa/erp/contractInfo/types.ts b/src/api/oa/erp/contractInfo/types.ts index c850dad..61e5674 100644 --- a/src/api/oa/erp/contractInfo/types.ts +++ b/src/api/oa/erp/contractInfo/types.ts @@ -229,6 +229,31 @@ export interface ContractInfoVO { */ originalContractId?: string | number; + /** + * 是否关联框架合同(1是 0否) + */ + isFrameworkContract?: string; + + /** + * 框架合同ID(关联合同) + */ + frameworkContractId?: string | number; + + /** + * 框架合同编号(冗余展示) + */ + frameworkContractCode?: string; + + /** + * 框架合同名称(冗余展示) + */ + frameworkContractName?: string; + + /** + * 框架合同有效期 + */ + frameworkValidPeriod?: string; + } export interface ContractInfoForm extends BaseEntity { @@ -462,6 +487,31 @@ export interface ContractInfoForm extends BaseEntity { */ originalContractId?: string | number; + /** + * 是否关联框架合同(1是 0否) + */ + isFrameworkContract?: string; + + /** + * 框架合同ID(关联合同) + */ + frameworkContractId?: string | number; + + /** + * 框架合同编号(冗余展示) + */ + frameworkContractCode?: string; + + /** + * 框架合同名称(冗余展示) + */ + frameworkContractName?: string; + + /** + * 框架合同有效期 + */ + frameworkValidPeriod?: string; + flowCode?: any; variables?: any; bizExt?: any; @@ -638,6 +688,21 @@ export interface ContractInfoQuery extends PageQuery { */ contractTemplateFlag?: string; + /** + * 是否关联框架合同(1是 0否) + */ + isFrameworkContract?: string; + + /** + * 框架合同ID(关联合同) + */ + frameworkContractId?: string | number; + + /** + * 框架合同有效期 + */ + frameworkValidPeriod?: string; + /** * 日期范围参数 */ diff --git a/src/views/oa/components/FrameworkContractSelectDialog.vue b/src/views/oa/components/FrameworkContractSelectDialog.vue new file mode 100644 index 0000000..e7a14c4 --- /dev/null +++ b/src/views/oa/components/FrameworkContractSelectDialog.vue @@ -0,0 +1,137 @@ + + + diff --git a/src/views/oa/erp/contractInfo/edit.vue b/src/views/oa/erp/contractInfo/edit.vue index cadc9e5..c24547e 100644 --- a/src/views/oa/erp/contractInfo/edit.vue +++ b/src/views/oa/erp/contractInfo/edit.vue @@ -52,6 +52,33 @@ + + + + {{ dict.label }} + + + + + + + + + + +
+ + 选择 + 清空 +
+
+
@@ -574,6 +601,12 @@ + + @@ -661,6 +694,7 @@ import SaleMaterialSelect from '@/components/SaleMaterialSelect/index.vue'; import SubmitVerify from '@/components/Process/submitVerify.vue'; import ApprovalRecord from '@/components/Process/approvalRecord.vue'; import ApprovalButton from '@/components/Process/approvalButton.vue'; +import FrameworkContractSelectDialog from '@/views/oa/components/FrameworkContractSelectDialog.vue'; import { ref } from 'vue'; import { allListDept, listDept } from '@/api/system/dept'; import { getCrmCustomerInfoList } from '@/api/oa/crm/customerInfo'; @@ -688,9 +722,20 @@ const { account_type, contract_status, material_flag, - contract_template_flag + contract_template_flag, + is_framework_contract } = toRefs( - proxy?.useDict('contract_category', 'business_direction', 'contract_flag', 'contract_type', 'account_type', 'contract_status', 'material_flag', 'contract_template_flag') + proxy?.useDict( + 'contract_category', + 'business_direction', + 'contract_flag', + 'contract_type', + 'account_type', + 'contract_status', + 'material_flag', + 'contract_template_flag', + 'is_framework_contract' + ) ); /** 付款方式下拉选项(存储中文) */ @@ -806,6 +851,8 @@ const getPaymentAccountListSelect = async () => { paymentAccountList.value = res.data || []; }; +const frameworkContractDialogVisible = ref(false); + // 合同物料对话框 const materialDialog = reactive({ visible: false, @@ -983,6 +1030,11 @@ const initFormData: ContractInfoFormEx = { contractManagerId: undefined, capitalizedAmount: undefined, contractTemplateFlag: '2', + isFrameworkContract: '0', + frameworkContractId: undefined, + frameworkContractCode: undefined, + frameworkContractName: undefined, + frameworkValidPeriod: undefined, flowCode: undefined, bizExt: undefined, variables: undefined, @@ -1006,7 +1058,20 @@ const data = reactive<{ form: ContractInfoFormEx; rules: any }>({ contractName: [{ required: true, message: '合同名称不能为空', trigger: 'blur' }], businessDirection: [{ required: true, message: '业务方向不能为空', trigger: 'blur' }], contractManagerId: [{ required: true, message: '合同负责人不能为空', trigger: 'blur' }], - contractTemplateFlag: [{ required: true, message: '合同模板标识不能为空', trigger: 'blur' }] + contractTemplateFlag: [{ required: true, message: '合同模板标识不能为空', trigger: 'blur' }], + isFrameworkContract: [{ required: true, message: '请选择关联框架合同', trigger: 'change' }], + frameworkValidPeriod: [ + { + validator: (_rule: any, _value: any, callback: (err?: Error) => void) => { + if (form.value.isFrameworkContract === '1' && !form.value.frameworkValidPeriod) { + callback(new Error('请填写框架合同有效期')); + return; + } + callback(); + }, + trigger: 'change' + } + ] } }); @@ -1028,6 +1093,12 @@ const ossIdString = computed({ const { form, rules } = toRefs(data); +const frameworkContractDisplay = computed(() => { + const code = form.value.frameworkContractCode || ''; + const name = form.value.frameworkContractName || ''; + return `${code} ${name}`.trim(); +}); + /** 是否为由「合同内容变更」生成的新合同(后端 originalContractId 非空) */ const isFromContentChangeContract = computed(() => { const id = (form.value as any).originalContractId; @@ -1046,6 +1117,19 @@ watch( } ); +watch( + () => form.value.contractCategory, + (newVal) => { + if (newVal === '3') { + form.value.isFrameworkContract = '0'; + form.value.frameworkContractId = undefined; + form.value.frameworkContractCode = undefined; + form.value.frameworkContractName = undefined; + form.value.frameworkValidPeriod = undefined; + } + } +); + // 生成合同编号 const generateContractCode = async () => { if (isCodeGenerated.value) return; // 如果已经生成过,直接返回 @@ -1443,6 +1527,58 @@ const loadSelectOptions = () => { getPaymentStageListSelect(); }; +const openFrameworkContractDialog = () => { + frameworkContractDialogVisible.value = true; +}; + +const onFrameworkContractConfirm = async (selected: any) => { + if (!selected?.contractId) return; + + const res = await getContractInfo(selected.contractId); + const frameworkDetail = (res?.data || {}) as any; + const currentContractId = form.value.contractId; + + const { contractMaterialList, contractPaymentMethodList, ...mainData } = frameworkDetail; + const excludeMainKeys = new Set(['contractId', 'contractCode', 'contractStatus', 'flowStatus', 'contractName', 'contractCategory', 'isFrameworkContract']); + Object.entries(mainData).forEach(([key, value]) => { + if (excludeMainKeys.has(key)) return; + (form.value as any)[key] = value; + }); + + // 子表赋值时排除各表主键,避免带入历史记录主键造成更新冲突 + (form.value as any).contractMaterialList = Array.isArray(contractMaterialList) + ? contractMaterialList.map((item: any) => { + const cloned = { ...item }; + delete cloned.contractMaterialId; + cloned.contractId = currentContractId; + return cloned; + }) + : []; + + (form.value as any).contractPaymentMethodList = Array.isArray(contractPaymentMethodList) + ? contractPaymentMethodList.map((item: any) => { + const cloned = { ...item }; + delete cloned.paymentMethodId; + cloned.contractId = currentContractId; + return cloned; + }) + : []; + + // 显式记录本次关联的框架合同 + form.value.frameworkContractId = selected.contractId; + form.value.frameworkContractCode = selected.contractCode; + form.value.frameworkContractName = selected.contractName; + + frameworkContractDialogVisible.value = false; + proxy?.$modal.msgSuccess('框架合同信息已带出'); +}; + +const clearFrameworkContract = () => { + form.value.frameworkContractId = undefined; + form.value.frameworkContractCode = undefined; + form.value.frameworkContractName = undefined; +}; + onMounted(async () => { nextTick(async () => { // 获取路由参数 diff --git a/src/views/oa/erp/contractInfo/index.vue b/src/views/oa/erp/contractInfo/index.vue index 9e94967..0dd8ffe 100644 --- a/src/views/oa/erp/contractInfo/index.vue +++ b/src/views/oa/erp/contractInfo/index.vue @@ -183,6 +183,18 @@ + + + + + +