1.1.22 合同模块新增“关联框架合同”相关前端逻辑。新增并抽离框架合同选择组件。新增关联框架合同、框架合同有效期、关联框架合同字段。框架合同则可以选择框架合同并带出框架合同信息。

dev
yinq 2 days ago
parent 204fb46f07
commit 30c6107bee

@ -16,6 +16,19 @@ export const listContractInfo = (query?: ContractInfoQuery): AxiosPromise<Contra
});
};
/**
*
* @param query
* @returns {*}
*/
export const listFrameworkContractInfo = (query?: ContractInfoQuery): AxiosPromise<ContractInfoVO[]> => {
return request({
url: '/oa/erp/contractInfo/framework/list',
method: 'get',
params: query
});
};
/**
*
* @param contractId

@ -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;
/**
*
*/

@ -0,0 +1,137 @@
<template>
<el-dialog v-model="dialogVisible" title="选择框架合同" width="900px" append-to-body>
<el-form :model="queryParams" :inline="true" label-width="90px" style="margin-bottom: 12px">
<el-form-item label="合同编号">
<el-input v-model="queryParams.contractCode" placeholder="请输入合同编号" clearable @keyup.enter="getFrameworkContractList" />
</el-form-item>
<el-form-item label="合同名称">
<el-input v-model="queryParams.contractName" placeholder="请输入合同名称" clearable @keyup.enter="getFrameworkContractList" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getFrameworkContractList"></el-button>
<el-button icon="Refresh" @click="resetFrameworkContractQuery"></el-button>
</el-form-item>
</el-form>
<el-table :data="frameworkContractList" v-loading="loading" border @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="合同编号" prop="contractCode" min-width="150" />
<el-table-column label="合同名称" prop="contractName" min-width="180" />
<el-table-column label="框架合同有效期" prop="frameworkValidPeriod" width="160">
<template #default="scope">
<span>{{ parseTime(scope.row.frameworkValidPeriod, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getFrameworkContractList"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="confirmSelection"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="FrameworkContractSelectDialog">
import { listFrameworkContractInfo } from '@/api/oa/erp/contractInfo';
import type { ContractInfoQuery, ContractInfoVO } from '@/api/oa/erp/contractInfo/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps<{
visible: boolean;
currentContractId?: string | number;
}>();
const emit = defineEmits<{
(e: 'update:visible', val: boolean): void;
(e: 'confirm', row: ContractInfoVO): void;
}>();
const dialogVisible = ref(false);
const loading = ref(false);
const total = ref(0);
const frameworkContractList = ref<ContractInfoVO[]>([]);
const selectedFrameworkContracts = ref<ContractInfoVO[]>([]);
const selectedFrameworkContract = ref<ContractInfoVO | null>(null);
const queryParams = reactive<ContractInfoQuery>({
pageNum: 1,
pageSize: 10,
contractCode: undefined,
contractName: undefined,
contractCategory: undefined,
contractStatus: undefined,
params: {}
});
watch(
() => props.visible,
(val) => {
dialogVisible.value = val;
if (val) {
selectedFrameworkContracts.value = [];
selectedFrameworkContract.value = null;
getFrameworkContractList();
}
},
{ immediate: true }
);
watch(dialogVisible, (val) => {
emit('update:visible', val);
});
const getFrameworkContractList = async () => {
loading.value = true;
try {
const res = await listFrameworkContractInfo(queryParams as any);
frameworkContractList.value = res.rows;
total.value = res.total || 0;
} finally {
loading.value = false;
}
};
const resetFrameworkContractQuery = () => {
queryParams.pageNum = 1;
queryParams.pageSize = 10;
queryParams.contractCode = undefined;
queryParams.contractName = undefined;
queryParams.contractCategory = '3';
queryParams.contractStatus = '3';
queryParams.isFrameworkContract = '1';
getFrameworkContractList();
};
const handleSelectionChange = (selection: ContractInfoVO[]) => {
selectedFrameworkContracts.value = selection || [];
if (!selection || selection.length === 0) {
selectedFrameworkContract.value = null;
return;
}
selectedFrameworkContract.value = selection[selection.length - 1];
};
const confirmSelection = () => {
if (!selectedFrameworkContract.value) {
proxy?.$modal.msgWarning('请先选择框架合同');
return;
}
if (selectedFrameworkContracts.value.length > 1) {
proxy?.$modal.msgWarning('只能选择一条框架合同');
return;
}
emit('confirm', selectedFrameworkContract.value);
dialogVisible.value = false;
};
</script>

@ -52,6 +52,33 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.contractCategory !== '3'">
<el-form-item label="关联框架合同" prop="isFrameworkContract">
<el-radio-group v-model="form.isFrameworkContract" :disabled="isFormDisabled">
<el-radio v-for="dict in is_framework_contract" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.contractCategory === '3'">
<el-form-item label="框架合同有效期" prop="frameworkValidPeriod">
<el-date-picker
v-model="form.frameworkValidPeriod"
type="date"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择框架合同有效期"
:disabled="isFormDisabled"
/>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.contractCategory !== '3' && form.isFrameworkContract === '1'">
<el-form-item label="关联框架合同" prop="frameworkContractId">
<div class="flex gap-2 items-center" style="width: 100%">
<el-input :model-value="frameworkContractDisplay" placeholder="请选择框架合同" readonly :disabled="isFormDisabled" />
<el-button type="primary" plain :disabled="isFormDisabled" @click="openFrameworkContractDialog"></el-button>
<el-button :disabled="isFormDisabled || !form.frameworkContractId" @click="clearFrameworkContract"></el-button>
</div>
</el-form-item>
</el-col>
<!-- <el-col :span="12">-->
<!-- <el-form-item label="合同类型" prop="contractType">-->
<!-- <el-select v-model="form.contractType" placeholder="请选择合同类型">-->
@ -574,6 +601,12 @@
<SaleMaterialSelect ref="saleMaterialSelectRef" :multiple="false"
@confirm-call-back="saleMaterialSelectCallBack"></SaleMaterialSelect>
<FrameworkContractSelectDialog
v-model:visible="frameworkContractDialogVisible"
:current-contract-id="form.contractId"
@confirm="onFrameworkContractConfirm"
/>
<!-- 添加SAP物料对话框 -->
<el-dialog title="添加SAP物料" v-model="materialInfoDialog.visible" width="800px" append-to-body>
<el-form ref="materialInfoFormRef" :model="materialInfoForm" :rules="materialInfoRules" label-width="120px">
@ -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<any>(
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 () => {
//

@ -183,6 +183,18 @@
<dict-tag :options="contract_template_flag" :value="scope.row.contractTemplateFlag" />
</template>
</el-table-column>
<el-table-column label="关联框架合同" align="center" prop="isFrameworkContract" width="120" v-if="columns[42].visible">
<template #default="scope">
<el-tag :type="scope.row.isFrameworkContract === '1' ? 'success' : 'info'">
{{ scope.row.isFrameworkContract === '1' ? '是' : '否' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="框架合同有效期" align="center" prop="frameworkValidPeriod" width="120" v-if="columns[43].visible">
<template #default="scope">
<span>{{ parseTime(scope.row.frameworkValidPeriod, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" v-if="columns[24].visible" />
<el-table-column label="激活标识" align="center" prop="activeFlag" v-if="columns[25].visible">
<template #default="scope">
@ -415,7 +427,9 @@ const columns = ref<FieldOption[]>([
{ key: 38, label: `合同负责人`, visible: true },
{ key: 39, label: `合同大写金额`, visible: false },
{ key: 40, label: `合同模板标识`, visible: true },
{ key: 41, label: `软控合同额(元)`, visible: true }
{ key: 41, label: `软控合同额(元)`, visible: true },
{ key: 42, label: `关联框架合同`, visible: true },
{ key: 43, label: `框架合同有效期`, visible: false }
]);
const data = reactive<{ queryParams: ContractInfoQuery }>({
@ -813,6 +827,9 @@ const canViewDetail = (row: ContractInfoVO) => {
/** 判断是否可以激活合同订单 */
const canActivateOrder = (row: ContractInfoVO) => {
if (String(row.contractCategory) === '3') {
return false;
}
// 3
if (row.contractStatus !== '3') {
return false;

Loading…
Cancel
Save