合同要素

This commit is contained in:
‘huanghaiixia’
2025-12-26 17:37:06 +08:00
parent 594ecb5309
commit 351ddc564f
19 changed files with 419 additions and 150 deletions

View File

@ -17,7 +17,7 @@ export const searchFormSchema: FormSchema[] = [
component: 'XjrSelect',
componentProps: {
datasourceType: 'dic',
params: { itemId: '1990669393069129729' },
params: { itemId: '2003815292742479874' },
labelField: 'name',
valueField: 'value',
@ -45,7 +45,7 @@ export const columns: BasicColumn[] = [
sorter: true,
},
{
dataIndex: 'relTypeCode',
dataIndex: 'relTypeName',
title: '关联类别',
componentType: 'input',
align: 'left',
@ -53,7 +53,7 @@ export const columns: BasicColumn[] = [
sorter: true,
},
{
dataIndex: 'kTypeCode1',
dataIndex: 'kTypeName1',
title: '合同类别',
componentType: 'input',
align: 'left',
@ -62,7 +62,7 @@ export const columns: BasicColumn[] = [
},
{
dataIndex: 'kTypeCode2',
dataIndex: 'kTypeName2',
title: '二级类别',
componentType: 'input',
align: 'left',
@ -89,16 +89,7 @@ export const columns: BasicColumn[] = [
},
{
dataIndex: 'periodTypeCode',
title: '合同期限',
componentType: 'input',
align: 'left',
sorter: true,
},
{
dataIndex: 'periodTypeCode',
dataIndex: 'periodTypeName',
title: '合同期限',
componentType: 'input',
align: 'left',
@ -125,7 +116,7 @@ export const columns: BasicColumn[] = [
},
{
dataIndex: 'curCode',
dataIndex: 'curName',
title: '币种',
componentType: 'select',
align: 'left',
@ -133,7 +124,7 @@ export const columns: BasicColumn[] = [
sorter: true,
},
{
dataIndex: 'amountTypeCode',
dataIndex: 'amountTypeName',
title: '合同金额类型',
componentType: 'select',
align: 'left',
@ -151,7 +142,7 @@ export const columns: BasicColumn[] = [
},
{
dataIndex: 'empId',
dataIndex: 'empName',
title: '业务联系人',
componentType: 'input',
align: 'left',
@ -160,7 +151,7 @@ export const columns: BasicColumn[] = [
},
{
dataIndex: 'bDeptId',
dataIndex: 'bDeptName',
title: '业务部门',
componentType: 'input',
align: 'left',
@ -169,7 +160,7 @@ export const columns: BasicColumn[] = [
},
{
dataIndex: 'approCode',
dataIndex: 'approName',
title: '状态',
componentType: 'input',
align: 'left',

View File

@ -6,7 +6,7 @@
<a-row>
<a-col :span="8">
<a-form-item label="合同号" name="kNo">
<a-input v-model:value="formState.kNo" :disabled="isDisable" style="width: 65%" /><a-button type="primary" @click="onAppro">关联签报</a-button>
<a-input v-model:value="formState.kNo" :disabled="isDisable" style="width: 65%" /><a-button v-if="!isDisable" type="primary" @click="onAppro">关联签报</a-button>
</a-form-item>
</a-col>
<a-col :span="16">
@ -43,7 +43,7 @@
</a-col>
<a-col :span="8">
<a-form-item label="合同期限" name="periodTypeCode">
<a-select v-model:value="formState.periodTypeCode" :disabled="isDisable" placeholder="请选择合同期限" style="width: 100%" allow-clear>
<a-select v-model:value="formState.periodTypeCode" :disabled="isDisable" placeholder="请选择合同期限" @change="periodTypeCodeChange" style="width: 100%" allow-clear>
<a-select-option v-for="item in optionSelect.periodTypeCodeList" :key="item.code" :value="item.code">
{{ item.name }}
</a-select-option>
@ -52,17 +52,17 @@
</a-col>
<a-col :span="8">
<a-form-item label="有效期开始" name="dateFrom">
<a-date-picker v-model:value="formState.dateFrom" style="width: 100%" :disabled-date="disabledDateStart" placeholder="请选择开始日期" />
<a-date-picker v-model:value="formState.dateFrom" style="width: 100%" :disabled="isDisable" :disabled-date="disabledDateStart" placeholder="请选择开始日期" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="有效期结束" name="dateTo">
<a-date-picker v-model:value="formState.dateTo" style="width: 100%" :disabled-date="disabledDateEnd" placeholder="请选择结束日期" />
<a-date-picker v-model:value="formState.dateTo" style="width: 100%" :disabled="isDisable" :disabled-date="disabledDateEnd" placeholder="请选择结束日期" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="起草日期" name="dateDraft">
<a-date-picker v-model:value="formState.dateDraft" style="width: 100%" placeholder="请选择起草日期" />
<a-date-picker v-model:value="formState.dateDraft" style="width: 100%" :disabled="isDisable" placeholder="请选择起草日期" />
</a-form-item>
</a-col>
<a-col :span="8">
@ -76,21 +76,21 @@
</a-col>
<a-col :span="8">
<a-form-item label="相对方数量" name="cpCount">
<a-input-number v-model:value="formState.cpCount" style="width: 100%" :precision="0" :min="0" :step="1" :max="20"/>
<a-input-number v-model:value="formState.cpCount" style="width: 100%" :disabled="isDisable" :precision="0" :min="0" :step="1" :max="20"/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="合同金额类型" name="amountTypeCode">
<a-select v-model:value="formState.amountTypeCode" :disabled="isDisable" placeholder="请选择合同金额类型" style="width: 100%" allow-clear>
<a-select v-model:value="formState.amountTypeCode" :disabled="isDisable" placeholder="请选择合同金额类型" @change="amountTypeCodeChange" style="width: 100%" allow-clear>
<a-select-option v-for="item in optionSelect.amountTypeCodeList" :key="item.code" :value="item.code">
{{ item.fullName }}
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="合同金额(万元)" name="amount">
<a-input-number v-model:value="formState.amount" style="width: 100%" :min="0" :disabled="isDisable" />
<a-input-number v-model:value="formState.amount" style="width: 100%" @blur="amountBlur(formState.amount)" :min="0" :disabled="isDisable" />
</a-form-item>
</a-col>
<a-col :span="8">
@ -107,7 +107,7 @@
<a-form-item label="结算类型" name="settleTypeCode">
<a-select v-model:value="formState.settleTypeCode" :disabled="isDisable" placeholder="请选择结算类型" style="width: 100%" allow-clear>
<a-select-option v-for="item in optionSelect.settleTypeCodeList" :key="item.code" :value="item.code">
{{ item.fullName }}
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
@ -164,7 +164,7 @@
</a-col>
<a-col :span="8">
<a-form-item label="联系电话" name="tel">
<a-input v-model:value="formState.tel" />
<a-input-search v-model:value="formState.tel" :disabled="isDisable" placeholder="请输入电话" />
</a-form-item>
</a-col>
<a-col :span="8">
@ -200,11 +200,12 @@
</a-card>
<a-card title="相对方信息" :bordered="false" >
<div style="width: 100%">
<a-button type="primary" style="margin-bottom: 10px" @click="onAppro">新增行</a-button>
<a-table style="width: 100%" :columns="columns" :data-source="dataList" :pagination="false" :scroll="{x: 2000}">
<a-button type="primary" style="margin-bottom: 10px" @click="addUser" v-if="!isDisable">新增行</a-button>
<a-table style="width: 100%" :columns="columns" :data-source="dataList" :pagination="false" :scroll="{x: 1000}">
<template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'operation'">
<!-- <a @click="btnCheck(record, index)">删除</a> -->
<a v-if="!isDisable" style="margin-right: 10px" @click="btnCheck('cp', 'edit', record, index)">编辑</a>
<a v-if="!isDisable" style="margin-right: 10px" @click="btnCheck('cp', 'delete', record, index)">删除</a>
</template>
</template>
</a-table>
@ -214,11 +215,15 @@
<UploadList :disabled="isDisable" :list="dataFile" :value="formState.filePath" :tableName="tableName" :columnName="columnName" @change="uploadListChange"/>
</a-card>
<a-card title="签报列表" :bordered="false" >
<a-button type="primary" style="margin-bottom: 10px" @click="onAppro">关联签报</a-button>
<a-button type="primary" style="margin-bottom: 10px" v-if="!isDisable" @click="onAppro">关联签报</a-button>
<a-table :columns="columnsAppro" :data-source="dataListAppro" :pagination="false">
<template #bodyCell="{ column, record, index }">
<template v-if="column.dataIndex === 'file'">
<a @click="handleDownload(record)">{{record.fileOrg}}</a>
</template>
<template v-if="column.dataIndex === 'operation'">
<!-- <a @click="btnCheck(record, index)">删除</a> -->
<a style="margin-right: 10px" @click="btnCheck('appro', 'view', record, index)">查看</a>
<a v-if="!isDisable" style="margin-right: 10px" @click="btnCheck('appro', 'delete', record, index)">删除</a>
</template>
</template>
</a-table>
@ -228,6 +233,7 @@
<deptUserModal @register="register" @success="handleSuccess"/>
<deptListModal @register="registerDept" @success="handleSuccessDept" />
<approListModal @register="registerAppro" @success="handleSuccessAppro" />
<contractFactUserModal @register="registerUser" @success="handleSuccessUser" />
</a-spin>
</template>
@ -242,7 +248,7 @@
import type { Rule } from 'ant-design-vue/es/form';
import { getDictionary } from '/@/api/sales/Customer';
import { useModal } from '/@/components/Modal';
import { addLngContractFact,updateLngContractFact,getAllCurrency, getLngContractFact } from '/@/api/contract/ContractFact';
import { addLngContractFact,updateLngContractFact,getAllCurrency,getAllUser, getLngContractFact } from '/@/api/contract/ContractFact';
import { getLngAppro,getCompDept } from '/@/api/approve/Appro';
import dayjs from 'dayjs';
import { getAppEnvConfig } from '/@/utils/env';
@ -251,6 +257,10 @@
import deptUserModal from '/@/components/common/deptUserModal.vue';
import deptListModal from '/@/components/common/deptListModal.vue';
import approListModal from '/@/components/common/approListModal.vue';
import contractFactUserModal from '/@/components/common/contractFactUserModal.vue';
import { amountToChinese } from '/@/utils/amountToChinese';
import { parseDownloadUrl} from '/@/api/system/file';
import { downloadByUrl } from '/@/utils/file/download';
import { Modal } from 'ant-design-vue';
import { useUserStore } from '/@/store/modules/user';
@ -292,7 +302,8 @@
const [register, { openModal:openModal}] = useModal();
const [registerDept, { openModal:openModalDept}] = useModal();
const [registerAppro, { openModal:openModalAppro}] = useModal();
const rules: Record<string, Rule[]> = {
const [registerUser, { openModal:openModalUser}] = useModal();
const rules= reactive({
kNo: [{ required: true, message: "该项为必填项", trigger: 'change' }],
kName: [{ required: true, message: "该项为必填项", trigger: 'change' }],
relTypeCode: [{ required: true, message: "该项为必填项", trigger: 'change' }],
@ -310,7 +321,7 @@
tel: [{ required: true, message: "该项为必填项", trigger: 'change' }],
bDeptName: [{ required: true, message: "该项为必填项", trigger: 'change' }],
};
});
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },
@ -318,13 +329,13 @@
const columns= ref([
{ title: t('序号'), dataIndex: 'index', key: 'index', sorter: true, customRender: (column) => `${column.index + 1}` ,width: 100},
{ title: t('相对方名称'), dataIndex: 'cpName', sorter: true, width:200},
{ title: t('相对方顺序'), dataIndex: 'sort', sorter: true, width: 180},
{ title: t('相对方顺序'), dataIndex: 'sort', sorter: true, width: 130},
{ title: t('相对方银行名称'), dataIndex: 'cpBankName', sorter: true, width: 200},
{ title: t('对方银行开户名'), dataIndex: 'cpBankAccountName', sorter: true, width: 300},
{ title: t('对方银行账号'), dataIndex: 'cpBankAccount', sorter: true, width: 300},
{ title: t('对方联系人姓名'), dataIndex: 'contactName', sorter: true, width: 300},
{ title: t('对方银行账号'), dataIndex: 'cpBankAccount', sorter: true, width: 200},
{ title: t('对方联系人姓名'), dataIndex: 'contactName', sorter: true, width: 200},
{ title: t('对方联系人电话'), dataIndex: 'contactTel', sorter: true, width: 200},
{ title: t('对方联系人邮箱'), dataIndex: 'contactEmail', sorter: true, width: 300},
{ title: t('对方联系人邮箱'), dataIndex: 'contactEmail', sorter: true, width: 200},
{ title: t('对方通讯地址'), dataIndex: 'contactAddress', sorter: true, width: 200},
{ title: t('备注'), dataIndex: 'note', sorter: true, width: 200},
{ title: t('操作'), dataIndex: 'operation', width: 120, fixed: 'right',align: 'center'},
@ -337,10 +348,10 @@
{ title: t('拟稿人'), dataIndex: 'empName', sorter: true, width: 140},
{ title: t('拟稿人所属部门'), dataIndex: 'bDeptName', sorter: true, width: 140},
{ title: t('拟稿时间'), dataIndex: 'dateAppro', sorter: true, width: 140},
{ title: t('附件'), dataIndex: 'contactTel', sorter: true, width: 140},
{ title: t('附件'), dataIndex: 'file', sorter: true, width: 140},
{ title: t('操作'), dataIndex: 'operation', width: 120, fixed: 'right',align: 'center'},
]);
const dataList = ref([{cpName: 88}])
const dataList = ref([])
const dataFile = ref([]);
const dataListAppro = ref([])
let optionSelect= reactive({
@ -365,6 +376,10 @@
() => props.disabled,
(val) => {
isDisable.value = val
if (val) {
let idx = columns.value.findIndex(v =>v.dataIndex == 'operation')
idx>-1 && columns.value.splice(idx, 1)
}
},
{
immediate: true
@ -378,8 +393,6 @@
formState.empName = userInfo.name
formState.empId = userInfo.id
formState.tel = userInfo.mobile
console.log(userInfo, 'userInfo')
}
});
@ -389,13 +402,17 @@
async function getInfo(id) {
spinning.value = true
try {
let data = await getLngAppro(id)
let data = await getLngContractFact(id)
spinning.value = false
Object.assign(formState, {...data})
Object.assign(dataFile.value, formState.lngFileUploadList || [])
Object.assign(dataList.value, formState.lngContractFactCpList || [])
Object.assign(dataListAppro.value, formState.lngApproVoList || [])
formState.dateDraft = formState.dateDraft ? dayjs(formState.dateDraft) : null
formState.dateFrom = formState.dateFrom ? dayjs(formState.dateFrom) : null
formState.dateTo = formState.dateTo ? dayjs(formState.dateTo) : null
periodTypeCodeChange(formState.periodTypeCode)
amountTypeCodeChange(formState.amountTypeCode)
} catch (error) {
spinning.value = false
}
@ -413,6 +430,7 @@
optionSelect.approCodeList = await getDictionary('LNG_APPRO')
optionSelect.curCodeList = await getAllCurrency()
// optionSelect.telList = await getAllUser()
if (!pageId.value) {
const res = await getCompDept(userInfo.id)
@ -424,6 +442,33 @@
}
}
const handleDownload = (info) => {
const url = parseDownloadUrl(info.response ? info.response.data.fileUrl : info.fileUrl);
const fileName = info.response ? info.response.data.fileOrg : info.fileOrg;
downloadByUrl({ url, fileName: fileName});
};
const periodTypeCodeChange = (val) => {
if (val === 'Y') {
rules.dateTo = [{ required: true, message: "该项为必填项", trigger: 'change' }]
rules.dateFrom = [{ required: true, message: "该项为必填项", trigger: 'change' }]
} else {
rules.dateTo = [{ required: false, message: "该项为必填项", trigger: 'change' }]
rules.dateFrom = [{ required: false, message: "该项为必填项", trigger: 'change' }]
}
}
const amountTypeCodeChange = (val) => {
if (val === 'Y') {
rules.curCode = [{ required: true, message: "该项为必填项", trigger: 'change' }]
rules.amount = [{ required: true, message: "该项为必填项", trigger: 'change' }]
} else {
rules.curCode = [{ required: false, message: "该项为必填项", trigger: 'change' }]
rules.amount = [{ required: false, message: "该项为必填项", trigger: 'change' }]
}
}
const amountBlur = (val) => {
if (!val) return
formState.amountCn = amountToChinese(Number(val)*10000)
}
const disabledDateStart = (startValue) => {
const endValue = formState?.dateTo;
if (!startValue || !endValue) {
@ -447,6 +492,10 @@
const onAppro = (val)=> {
openModalAppro(true,{isUpdate: false})
}
const addUser = (val)=> {
openModalUser(true,{isUpdate: false})
}
const handleSuccess = (val) => {
formState.empName = val[0].name
formState.empId = val[0].id
@ -460,6 +509,10 @@
formState.comId = info.id
}
const handleSuccessAppro = (val) =>{
val.forEach(v => {
v.approId = v.id
v.id = null
})
if (!dataListAppro.value.length) {
dataListAppro.value = val
return
@ -468,7 +521,7 @@
val.forEach(v => {
dataListAppro.value.forEach(i => {
if (v.code == i.code){
message.warning(v.code + '已重复')
message.warning(v.code + '已重复, 签报不需要重复选择')
} else {
arr.push(v)
}
@ -476,6 +529,45 @@
})
dataListAppro.value = unique([...dataListAppro.value, ...arr], 'code')
}
const handleSuccessUser = (val) => {
if (curIdx.value != null) {
dataList.value[curIdx.value] = {...val}
return
}
dataList.value.push({...val})
}
const btnCheck = (type, btn, record, index) => {
curIdx.value = null
if (type == 'cp') {
if (btn == 'delete') {
dataList.value.splice(index, 1)
}
if (btn == 'edit') {
openModalUser(true, {record: record,isUpdate: true});
}
}
// 签报
if (type == 'appro') {
if (btn == 'delete') {
Modal.confirm({
title: '提示信息',
content: '是否取消关联?',
okText: '确认',
cancelText: '取消',
onOk() {
dataListAppro.value.splice(index, 1);
},
onCancel() {}
});
}
if (btn == 'view') {
}
}
}
function unique(arr, u_key) {
const map = new Map()
arr.forEach((item, index) => {
@ -494,9 +586,19 @@
async function handleSubmit(type) {
try {
await formRef.value.validateFields();
if (Number(formState.cpCount) !== dataList.value.length) {
notification.warning({
message: 'Tip',
description: '相对数量需与相对方信息个数一致'
});
return
}
let obj = {
...formState,
lngFileUploadList: dataFile.value
lngFileUploadList: dataFile.value,
lngContractFactCpList: dataList.value,
lngContractApproRelList: dataListAppro.value
}
spinning.value = true;

View File

@ -76,7 +76,7 @@
//所有按钮
const buttons = ref([{"name":"新增","code":"add","icon":"ant-design:plus-outlined","isDefault":true,"isUse":true,"type":"primary"},{"name":"编辑","code":"edit","icon":"ant-design:form-outlined","isDefault":true,"isUse":true},{"name":"刷新","code":"refresh","icon":"ant-design:reload-outlined","isDefault":true,"isUse":true},{"name":"查看","code":"view","icon":"ant-design:eye-outlined","isDefault":true,"isUse":true},{"name":"发起审批","code":"startwork","icon":"ant-design:form-outlined","isDefault":true,"isUse":true},{"name":"查看流转记录","code":"flowRecord","icon":"ant-design:form-outlined","isDefault":true,"isUse":true},{"name":"变更","code":"update","icon":"ant-design:edit-filled","isDefault":false,"isUse":true},{"name":"删除","code":"delete","icon":"ant-design:delete-outlined","isDefault":true,"isUse":true}]);
//展示在列表内的按钮
const actionButtons = ref<string[]>(['view', 'edit','datalog', 'copyData', 'delete', 'startwork','flowRecord']);
const actionButtons = ref<string[]>(['view', 'edit','datalog', 'copyData', 'delete','update', 'startwork','flowRecord']);
const buttonConfigs = computed(()=>{
return filterButtonAuth(buttons.value);
})
@ -89,7 +89,7 @@
return buttonConfigs.value?.filter((x) => actionButtons.value.includes(x.code));
});
const btnEvent = {add : handleAdd,edit : handleEdit,refresh : handleRefresh,view : handleView,startwork : handleStartwork,flowRecord : handleFlowRecord,delete : handleDelete,}
const btnEvent = {add : handleAdd,edit : handleEdit,refresh : handleRefresh,view : handleView,startwork : handleStartwork,flowRecord : handleFlowRecord,delete : handleDelete,update: handleUpdate}
const { currentRoute } = useRouter();
const router = useRouter();
@ -121,10 +121,8 @@
gutter: 16,
},
schemas: customSearchFormSchema,
fieldMapToTime: [['dateDraft', ['dateDraftStart', 'dateDraftEnd'], 'YYYY-MM-DD ', true],
['dateFrom', ['dateFromStart', 'dateFromEnd'], 'YYYY-MM-DD HH:mm:ss ', true],
['dateTo', ['dateToStart', 'dateToEnd'], 'YYYY-MM-DD HH:mm:ss ', true],],
showResetButton: false,
fieldMapToTime: [],
showResetButton: true,
},
beforeFetch: (params) => {
return { ...params, FormId: formIdComputedRef.value, PK: 'id' };
@ -161,7 +159,8 @@
query: {
taskId: taskIds[0],
formName: formName,
formId:currentRoute.value.meta.formId
formId:currentRoute.value.meta.formId,
id: record.id
}
});
} else if (schemaId && !taskIds && processId) {
@ -171,18 +170,32 @@
readonly: 1,
taskId: '',
formName: formName,
formId:currentRoute.value.meta.formId
formId:currentRoute.value.meta.formId,
id: record.id
}
});
} else {
router.push({
path: '/form/ContractFact/' + record.id + '/viewForm',
query: {
formPath: 'contract/ContractFact',
formName: formName,
formId:currentRoute.value.meta.formId
}
});
if (schemaIdComputedRef.value) {
router.push({
path: '/flow/' + schemaIdComputedRef.value + '/0/createFlow',
query: {
formPath: 'contract/ContractFact',
formName: formName,
formId:currentRoute.value.meta.formId,
type:'edit',
id: record.id,
disabled: 1,
}
});
}
// router.push({
// path: '/form/ContractFact/' + record.id + '/viewForm',
// query: {
// formPath: 'contract/ContractFact',
// formName: formName,
// formId:currentRoute.value.meta.formId
// }
// });
}
}
@ -213,15 +226,42 @@
}
function handleEdit(record: Recordable) {
router.push({
path: '/form/ContractFact/' + record.id + '/updateForm',
query: {
if (schemaIdComputedRef.value) {
router.push({
path: '/flow/' + schemaIdComputedRef.value + '/0/createFlow',
query: {
formPath: 'contract/ContractFact',
formName: formName,
formId:currentRoute.value.meta.formId
formId:currentRoute.value.meta.formId,
type:'edit',
id: record.id
}
});
} else {
router.push({
path: '/form/ContractFact/' + record.id + '/updateForm',
query: {
formPath: 'contract/ContractFact',
formName: formName,
formId:currentRoute.value.meta.formId
}
});
}
}
function handleUpdate(record: Recordable) {
const { processId, taskIds, schemaId, status } = record.workflowData || {};
router.push({
path: '/flow/' + schemaId + '/' + processId + '/approveFlow',
query: {
readonly: 1,
taskId: '',
formName: formName,
formId:currentRoute.value.meta.formId,
id: record.id,
status
}
});
}
function handleDelete(record: Recordable) {
deleteList([record.id]);
@ -314,6 +354,10 @@
actionsList = actionsList.concat(editAndDelBtn);
}
}
if (record.approCode !== 'YSP') {
let idx = actionsList.findIndex(v =>v.tooltip == '变更')
idx>-1 && actionsList.splice(idx, 1)
}
return actionsList;
}
function handleStartwork(record: Recordable) {