前端完善

This commit is contained in:
2026-05-29 15:26:25 +08:00
parent dcbd86f8f8
commit 2fba4fbba7
12 changed files with 1829 additions and 736 deletions
@@ -71,11 +71,12 @@
v-for="field in launchFieldList"
:key="field.key"
:label="field.label"
required
:required="!field.readonly"
>
<a-input
:value="getLaunchFieldValue(field.key)"
:placeholder="`请输入${field.label}`"
:readonly="field.readonly"
@update:value="setLaunchFieldValue(field.key, $event)"
/>
</a-form-item>
@@ -196,6 +197,20 @@ import {
downloadTemplateFile,
queryPublishedManifestList,
} from "@/api/manifest.js";
import { uploadLaunchFile } from "@/api/launch.js";
import {
contractSourceOptions,
contractTypeOptions,
currencyOptions,
dateTypeOptions,
extraAmountFieldOptions,
getOptionLabel,
isElectronOptions,
paymentDirectionOptions,
sealTypeOptions,
textSourceOptions,
valuationModeOptions,
} from "../contractLaunchOptions.js";
// ========================================================================
// 以下为表单模型 + 字典 + 工具函数,直接内联在此文件中。
@@ -208,68 +223,68 @@ const contractCreateModeOptions = [
{ label: '手动创建', value: 'manual' },
]
// ========== 合同类型选项 ==========
const contractTypeOptions = [
{ label: '采购合同', value: '采购合同' },
{ label: '销售合同', value: '销售合同' },
{ label: '服务合同', value: '服务合同' },
{ label: '框架合同', value: '框架合同' },
]
// ========== 付款方式选项 ==========
const paymentMethodOptions = [
{ label: '银行转账(30%预付款,70%验收后支付)', value: '银行转账(30%预付款,70%验收后支付)' },
{ label: '银行转账(按月结算)', value: '银行转账(按月结算)' },
{ label: '银行转账(一次性结清)', value: '银行转账(一次性结清)' },
]
// ========== 计价方式选项 ==========
const valuationModeOptions = [
{ label: '无金额', value: '0' },
{ label: '固定总价', value: '1' },
{ label: '预估总价', value: '2' },
{ label: '无法预估总价', value: '3' },
{ label: '固定单价', value: '4' },
]
// ========== 币种选项 ==========
const currencyOptions = [
{ label: '人民币', value: 'RMB' },
{ label: '美元', value: 'USD' },
{ label: '港币', value: 'HKD' },
{ label: '欧元', value: 'EUR' },
{ label: '印尼盾', value: 'IDR' },
]
// ========== 签订方式选项 ==========
const sealTypeOptions = [
{ label: '公章', value: 'GZ' },
{ label: '合同专用章', value: 'HTZYZ' },
{ label: '公章+法定代表人私章', value: 'GZFDDBRSZ' },
{ label: '公章+法定代表人签字', value: 'GZFDDBRQZ' },
{ label: '公章+被授权人签字', value: 'GZBSQRQZ' },
{ label: '合同专用章+被授权人签字', value: 'HTZYZBSQRQZ' },
{ label: '合同专用章+法定代表人签字', value: 'HTZYZFDDBRQZ' },
{ label: '其他', value: 'QT' },
]
// ========== 可绑定业务字段列表(用于映射下拉和展示) ==========
const templateFieldList = [
{ value: 'contractName', label: '合同名称' },
{ value: 'contractCode', label: '合同编码' },
{ value: 'contractType', label: '合同类型' },
{ value: 'contractTypeCode', label: '合同类型编码' },
{ value: 'contractAmountDisplay', label: '合同金额' },
{ value: 'contractAmount', label: '合同金额数字' },
{ value: 'effectiveStart', label: '有效期起' },
{ value: 'effectiveEnd', label: '有效期止' },
{ value: 'effectivePeriod', label: '有效期区间' },
{ value: 'contractPeriodTypeLabel', label: '合同期限类型' },
{ value: 'periodExplain', label: '期限说明' },
{ value: 'paymentMethod', label: '付款方式' },
{ value: 'paymentDirectionLabel', label: '收支方向' },
{ value: 'valuationModeLabel', label: '计价方式' },
{ value: 'currencyNameLabel', label: '币种' },
{ value: 'sealTypeLabel', label: '签订方式' },
{ value: 'textSourceLabel', label: '文本来源' },
{ value: 'isElectronLabel', label: '签署方式' },
{ value: 'contractSourceLabel', label: '合同来源' },
{ value: 'dateTypeLabel', label: '固定期限日期类型' },
{ value: 'mandateType', label: '委托类型' },
{ value: 'cargoType', label: '货种' },
{ value: 'primaryContent', label: '合同标的说明' },
{ value: 'amountExplain', label: '业务备注' },
{ value: 'amountExplain', label: '金额说明' },
{ value: 'contractGistRemark', label: '签订依据说明' },
{ value: 'bodySummary', label: '正文摘要' },
{ value: 'assistDept', label: '协助部门' },
{ value: 'executorAccount', label: '合同执行人' },
{ value: 'selfCode', label: '二级单位合同编码' },
{ value: 'mainContractCode', label: '主合同编码' },
{ value: 'signingSubjectCode', label: '签约主体编码' },
{ value: 'invoiceDate', label: '开票时间' },
{ value: 'receiveDate', label: '收款时间' },
{ value: 'partyAName', label: '甲方名称' },
{ value: 'partyBName', label: '乙方名称' },
{ value: 'partyCName', label: '丙方名称' },
{ value: 'partyAContactName', label: '甲方联系人' },
{ value: 'partyBContactName', label: '乙方联系人' },
{ value: 'partyCContactName', label: '丙方联系人' },
{ value: 'partyAContactPhone', label: '甲方电话' },
{ value: 'partyBContactPhone', label: '乙方电话' },
{ value: 'partyCContactPhone', label: '丙方电话' },
{ value: 'partyAAddress', label: '甲方地址' },
{ value: 'partyBAddress', label: '乙方地址' },
{ value: 'partyCAddress', label: '丙方地址' },
{ value: 'partyACreditCode', label: '甲方统一社会信用代码' },
{ value: 'partyBCreditCode', label: '乙方统一社会信用代码' },
{ value: 'partyCCreditCode', label: '丙方统一社会信用代码' },
{ value: 'partyABankName', label: '甲方开户行' },
{ value: 'partyBBankName', label: '乙方开户行' },
{ value: 'partyCBankName', label: '丙方开户行' },
{ value: 'partyABankAccount', label: '甲方银行账号' },
{ value: 'partyBBankAccount', label: '乙方银行账号' },
{ value: 'partyCBankAccount', label: '丙方银行账号' },
{ value: 'counterpartySummary', label: '合同方摘要' },
{ value: 'attachmentSummary', label: '附件情况' },
{ value: 'contractGistFileSummary', label: '签订依据附件' },
{ value: 'contractBodyFileName', label: '合同正文文件名' },
{ value: 'extraAmountSummary', label: '额外金额' },
{ value: 'performancePlanSummary', label: '履行计划' },
{ value: 'templateLabel', label: '模板名称' },
{ value: 'signDate', label: '签署日期' },
]
@@ -283,19 +298,154 @@ function formatContractAmount(value) {
}).format(Number(value))} 元`
}
function getContractPeriodTypeLabel(value) {
if (value === '1') return '无固定期限'
return '固定期限'
}
function normalizeFileItem(item = {}) {
return {
uid: item.uid || `file_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`,
name: item.name || item.fileName || '',
size: item.size ?? item.fileSize ?? 0,
status: item.status || 'done',
filePath: item.filePath || '',
fileType: item.fileType || '',
fileCategory: item.fileCategory || '',
}
}
function splitFilesByCategory(source = {}) {
const sourceFiles = source.fileList || []
const bodyFile = sourceFiles.find((item) => item.fileCategory === 'body') || {}
return {
contractBodyFileName:
source.contractBodyFileName ||
source.contractTextFileName ||
bodyFile.fileName ||
'',
contractBodyFilePath:
source.contractBodyFilePath ||
source.contractTextFilePath ||
bodyFile.filePath ||
'',
contractBodyFileType:
source.contractBodyFileType ||
source.contractTextFileType ||
bodyFile.fileType ||
'',
contractBodyFileSize:
source.contractBodyFileSize ??
source.contractTextFileSize ??
bodyFile.fileSize ??
null,
otherAttachmentList: source.otherAttachmentList?.length
? source.otherAttachmentList.map(normalizeFileItem)
: sourceFiles
.filter((item) => item.fileCategory === 'other')
.map(normalizeFileItem),
contractGistFileList: source.contractGistFileList?.length
? source.contractGistFileList.map(normalizeFileItem)
: sourceFiles
.filter((item) => item.fileCategory === 'gist')
.map(normalizeFileItem),
}
}
function formatFileSummary(fileList = []) {
return fileList.length
? fileList.map((item) => item.name || item.fileName).filter(Boolean).join('')
: '暂无附件'
}
function buildExtraAmountSummary(extraAmounts = {}) {
const parts = extraAmountFieldOptions
.filter((item) => extraAmounts[`${item.key}Enabled`])
.map((item) => `${item.label}${formatContractAmount(extraAmounts[item.key]) || '0.00 元'}`)
return parts.length ? parts.join('') : '无'
}
function restoreExtraAmounts(source = {}, current = {}) {
const result = { ...current, ...(source.extraAmounts || {}) }
const selectedCodes = String(source.ewAmountType || '')
.split(',')
.map((item) => item.trim())
.filter(Boolean)
extraAmountFieldOptions.forEach((item) => {
const amount = source[item.amountField]
if (selectedCodes.includes(item.code) || amount || amount === 0) {
result[`${item.key}Enabled`] = selectedCodes.includes(item.code) || amount > 0
if (amount !== undefined && amount !== null) {
result[item.key] = amount
}
}
})
return result
}
function buildPerformancePlanSummary(list = []) {
if (!list.length) return '暂无履行计划'
return list
.map((item, index) => {
const money = item.planMoney || item.planMoney === 0 ? `,金额${formatContractAmount(item.planMoney)}` : ''
return `${index + 1}. ${item.planMatter || '未填写事项'}${item.planWhere || '未填写条件'}${item.planTime || '未填写日期'}${money}`
})
.join('\n')
}
// ========== 合同方相关函数 ==========
/** 深拷贝合同方状态 */
function copyPartyState(input) {
const source = input || {}
const listState = buildPartyStateFromList(source.partyList)
return {
isThreePartyContract: Boolean(source.isThreePartyContract),
partyA: { roleKey: 'A', roleName: '甲方', companyName: '', ...(source.partyA || source.parties?.A || {}) },
partyB: { roleKey: 'B', roleName: '乙方', companyName: '', ...(source.partyB || source.parties?.B || {}) },
partyC: { roleKey: 'C', roleName: '丙方', companyName: '', ...(source.partyC || source.parties?.C || {}) },
partyA: { roleKey: 'A', roleName: '甲方', companyName: '', ...(source.partyA || source.parties?.A || {}), ...(listState?.partyA || {}) },
partyB: { roleKey: 'B', roleName: '乙方', companyName: '', ...(source.partyB || source.parties?.B || {}), ...(listState?.partyB || {}) },
partyC: { roleKey: 'C', roleName: '丙方', companyName: '', ...(source.partyC || source.parties?.C || {}), ...(listState?.partyC || {}) },
...(listState ? { isThreePartyContract: listState.isThreePartyContract } : {}),
}
}
function mapLaunchPartyToFormParty(item = {}) {
return {
roleKey: item.roleCode || 'B',
roleName: item.roleCode === 'A' ? '甲方' : item.roleCode === 'C' ? '丙方' : '乙方',
partnerId: item.partnerId || null,
oppositeId: item.oppositeId || '',
companyName: item.companyName || '',
companyType: item.companyType || '',
oppCharacter: item.oppositeCharacter || '',
contactName: item.contactName || '',
contactPhone: item.contactPhone || '',
contactEmail: item.contactEmail || '',
contactAddress: item.contactAddress || '',
registeredAddress: item.registeredAddress || '',
legalRepresentative: item.legalRepresentative || '',
creditCode: item.creditCode || '',
bankName: item.bankName || '',
bankAccount: item.bankAccount || '',
naturalPersonIdType: item.naturalPersonIdType || '',
naturalPersonIdNumber: item.naturalPersonIdNumber || '',
isGroupInternal: item.isGroupInternal === '1' || item.isGroupInternal === true,
isHongKongMacaoTaiwan: item.isHongKongMacaoTaiwan === '1' || item.isHongKongMacaoTaiwan === true,
}
}
function buildPartyStateFromList(list = []) {
if (!Array.isArray(list) || !list.length) return null
const state = { partyA: {}, partyB: {}, partyC: {}, isThreePartyContract: false }
list.forEach((item) => {
const key = item.roleCode === 'A' ? 'partyA' : item.roleCode === 'C' ? 'partyC' : 'partyB'
state[key] = mapLaunchPartyToFormParty(item)
})
state.isThreePartyContract = Boolean(state.partyB.companyName && state.partyC.companyName)
return state
}
/** 获取有效的合同方列表 */
function getPartyList(partyState) {
const state = copyPartyState(partyState)
@@ -366,6 +516,8 @@ function createPerformancePlan() {
planTime: '',
planDay: 0,
planMoney: '',
planSubjectCode: '',
planSubjectName: '',
planDetail: '',
}
}
@@ -386,6 +538,11 @@ function createContractFormData() {
contractPeriodType: '0', // 合同期限类型: 0-固定期限 1-无固定期限
periodExplain: '', // 期限说明(无固定期限时填写)
paymentMethod: '', // 付款方式
paymentDirection: '0', // 收支方向
isElectron: '1', // 签署方式: 0-纸质 1-电子
textSource: 'standardText', // 文本来源
contractSource: 'ECP', // 合同来源
dateType: '0', // 固定期间日期类型:0-年 1-月 2-日
valuationMode: '', // 计价方式: 0-无金额 1-固定总价 2-预估总价 3-无法预估总价 4-固定单价
currencyName: '', // 币种: RMB/USD/HKD/EUR/IDR
sealType: '', // 签订方式: GZ/HTZYZ/...
@@ -393,13 +550,24 @@ function createContractFormData() {
cargoType: '', // 货种
primaryContent: '', // 合同主要内容
amountExplain: '', // 金额说明
contractGistRemark: '', // 签订依据说明
bodySummary: '', // 正文摘要
assistDept: '', // 协助部门
executorAccount: '', // 合同执行人手机号
selfCode: '', // 二级单位合同编码
mainContractCode: '', // 主合同编码
signingSubjectCode: '', // 签约主体编码
invoiceDate: '', // 开票时间
receiveDate: '', // 收款时间
// 文件
contractBodyFileName: '', // 合同正文文件名
contractBodyFilePath: '',
contractBodyFileType: '',
contractBodyFileSize: null,
contractBodyArrayBuffer: null, // 合同正文文件二进制
otherAttachmentList: [], // 其他附件列表
contractGistFileList: [], // 签订依据附件列表
// 合同方
partyState: {
@@ -424,6 +592,11 @@ function createContractFormData() {
advanceEnabled: false, advance: 0,
guaranteeEnabled: false, guarantee: 0,
},
ewAmountType: '',
djAmount: 0,
yjAmount: 0,
yfkAmount: 0,
bzjAmount: 0,
// 履行计划
performancePlans: [],
@@ -437,17 +610,23 @@ function createContractFormData() {
function copyContractFormData(data = {}) {
const form = createContractFormData()
const source = data || {}
const fileState = splitFilesByCategory(source)
form.contractName = source.contractName ?? form.contractName
form.contractCode = source.contractCode ?? form.contractCode
form.contractType = source.contractType ?? form.contractType
form.contractTypeCode = source.contractTypeCode ?? source.contractType ?? form.contractTypeCode
form.contractAmount = source.contractAmount ?? form.contractAmount
form.effectiveStart = source.effectiveStart ?? form.effectiveStart
form.effectiveEnd = source.effectiveEnd ?? form.effectiveEnd
form.effectiveStart = source.effectiveStart ? String(source.effectiveStart).slice(0, 10) : form.effectiveStart
form.effectiveEnd = source.effectiveEnd ? String(source.effectiveEnd).slice(0, 10) : form.effectiveEnd
form.contractPeriodType = source.contractPeriodType ?? form.contractPeriodType
form.periodExplain = source.periodExplain ?? form.periodExplain
form.paymentMethod = source.paymentMethod ?? form.paymentMethod
form.paymentDirection = source.paymentDirection ?? form.paymentDirection
form.isElectron = source.isElectron ?? form.isElectron
form.textSource = source.textSource ?? form.textSource
form.contractSource = source.contractSource ?? form.contractSource
form.dateType = source.dateType ?? form.dateType
form.valuationMode = source.valuationMode ?? form.valuationMode
form.currencyName = source.currencyName ?? form.currencyName
form.sealType = source.sealType ?? form.sealType
@@ -455,31 +634,48 @@ function copyContractFormData(data = {}) {
form.cargoType = source.cargoType ?? form.cargoType
form.primaryContent = source.primaryContent ?? form.primaryContent
form.amountExplain = source.amountExplain ?? form.amountExplain
form.assistDept = source.assistDept ?? form.assistDept
form.contractGistRemark = source.contractGistRemark ?? form.contractGistRemark
form.bodySummary = source.bodySummary ?? form.bodySummary
form.assistDept = source.assistDept ?? source.assistDepartmentName ?? form.assistDept
form.executorAccount = source.executorAccount ?? form.executorAccount
form.contractBodyFileName = source.contractBodyFileName ?? form.contractBodyFileName
form.selfCode = source.selfCode ?? form.selfCode
form.mainContractCode = source.mainContractCode ?? form.mainContractCode
form.signingSubjectCode = source.signingSubjectCode ?? source.orgId ?? form.signingSubjectCode
form.invoiceDate = source.invoiceDate ? String(source.invoiceDate).slice(0, 10) : form.invoiceDate
form.receiveDate = source.receiveDate ? String(source.receiveDate).slice(0, 10) : form.receiveDate
form.contractBodyFileName = fileState.contractBodyFileName
form.contractBodyFilePath = fileState.contractBodyFilePath
form.contractBodyFileType = fileState.contractBodyFileType
form.contractBodyFileSize = fileState.contractBodyFileSize
form.contractBodyArrayBuffer = source.contractBodyArrayBuffer
? (source.contractBodyArrayBuffer instanceof ArrayBuffer ? source.contractBodyArrayBuffer.slice(0) : null)
: null
form.otherAttachmentList = [...(source.otherAttachmentList || source.attachmentList || [])]
form.partyState = copyPartyState(source.partyState)
form.otherAttachmentList = fileState.otherAttachmentList
form.contractGistFileList = fileState.contractGistFileList
form.partyState = copyPartyState(source.partyState || source)
form.isInvolveHongKongMacaoTaiwan = source.isInvolveHongKongMacaoTaiwan ?? form.isInvolveHongKongMacaoTaiwan
form.isPublicTender = source.isPublicTender ?? form.isPublicTender
form.isForeignRelatedSubject = source.isForeignRelatedSubject ?? form.isForeignRelatedSubject
form.isIncludedInCurrentYearBudget = source.isIncludedInCurrentYearBudget ?? form.isIncludedInCurrentYearBudget
form.isShared = source.isShared ?? form.isShared
form.isMajorContract = source.isMajorContract ?? form.isMajorContract
form.signDate = source.signDate ?? form.signDate
form.signDate = source.signDate ? String(source.signDate).slice(0, 10) : form.signDate
form.extraAmounts = {
depositEnabled: false, deposit: 0,
pledgeEnabled: false, pledge: 0,
advanceEnabled: false, advance: 0,
guaranteeEnabled: false, guarantee: 0,
...(source.extraAmounts || {}),
}
form.extraAmounts = restoreExtraAmounts(source, form.extraAmounts)
form.ewAmountType = source.ewAmountType ?? form.ewAmountType
form.djAmount = source.djAmount ?? form.djAmount
form.yjAmount = source.yjAmount ?? form.yjAmount
form.yfkAmount = source.yfkAmount ?? form.yfkAmount
form.bzjAmount = source.bzjAmount ?? form.bzjAmount
form.performancePlans = (source.performancePlans || []).map((item) => ({
...createPerformancePlan(),
...item,
planTime: item.planTime ? String(item.planTime).slice(0, 10) : '',
}))
return form
@@ -490,28 +686,77 @@ function copyContractFormData(data = {}) {
/** 将合同表单数据转换为模板变量字典(用于 docxtemplater 渲染) */
function buildTemplatePreviewData(formData, templateLabel = '', creationMode = 'template') {
const form = copyContractFormData(formData)
const attachmentSummary = form.otherAttachmentList.length
? form.otherAttachmentList.map((item) => item.name).join('')
: '暂无附件'
const attachmentSummary = formatFileSummary(form.otherAttachmentList)
const contractGistFileSummary = formatFileSummary(form.contractGistFileList)
const partyA = form.partyState.partyA || {}
const partyB = form.partyState.partyB || {}
const partyC = form.partyState.partyC || {}
return {
contractName: form.contractName || '未填写',
contractCode: form.contractCode || '未填写',
contractType: form.contractType || '未填写',
contractType: getOptionLabel(contractTypeOptions, form.contractType) || form.contractType || '未填写',
contractTypeCode: form.contractTypeCode || '',
contractAmountDisplay: formatContractAmount(form.contractAmount),
contractAmount: form.contractAmount ?? '',
effectiveStart: form.effectiveStart || '--',
effectiveEnd: form.effectiveEnd || '--',
effectivePeriod: `${form.effectiveStart || '--'}${form.effectiveEnd || '--'}`,
effectivePeriod: form.contractPeriodType === '1'
? form.periodExplain || '无固定期限'
: `${form.effectiveStart || '--'}${form.effectiveEnd || '--'}`,
contractPeriodTypeLabel: getContractPeriodTypeLabel(form.contractPeriodType),
periodExplain: form.periodExplain || '',
paymentMethod: form.paymentMethod || '未填写',
paymentDirectionLabel: getOptionLabel(paymentDirectionOptions, form.paymentDirection),
valuationModeLabel: getOptionLabel(valuationModeOptions, form.valuationMode),
currencyNameLabel: getOptionLabel(currencyOptions, form.currencyName),
sealTypeLabel: getOptionLabel(sealTypeOptions, form.sealType),
textSourceLabel: getOptionLabel(textSourceOptions, form.textSource),
isElectronLabel: getOptionLabel(isElectronOptions, form.isElectron),
contractSourceLabel: getOptionLabel(contractSourceOptions, form.contractSource),
dateTypeLabel: getOptionLabel(dateTypeOptions, form.dateType),
mandateType: form.mandateType || '',
cargoType: form.cargoType || '',
primaryContent: form.primaryContent || form.cargoType || '',
amountExplain: form.amountExplain || '',
contractGistRemark: form.contractGistRemark || '',
bodySummary: form.bodySummary || form.primaryContent || '',
assistDept: form.assistDept || '',
executorAccount: form.executorAccount || '',
selfCode: form.selfCode || '',
mainContractCode: form.mainContractCode || '',
signingSubjectCode: form.signingSubjectCode || '',
invoiceDate: form.invoiceDate || '',
receiveDate: form.receiveDate || '',
counterpartySummary: getPartySummary(form.partyState),
attachmentSummary,
contractGistFileSummary,
contractBodyFileName: form.contractBodyFileName || '',
extraAmountSummary: buildExtraAmountSummary(form.extraAmounts),
performancePlanSummary: buildPerformancePlanSummary(form.performancePlans),
templateLabel: templateLabel || (creationMode === 'manual' ? '手动创建' : ''),
signDate: form.signDate || dayjs().format('YYYY-MM-DD'),
partyAName: form.partyState.partyA.companyName || '',
partyBName: form.partyState.partyB.companyName || '',
partyCName: form.partyState.isThreePartyContract ? form.partyState.partyC.companyName || '' : '',
partyAName: partyA.companyName || '',
partyBName: partyB.companyName || '',
partyCName: form.partyState.isThreePartyContract ? partyC.companyName || '' : '',
partyAContactName: partyA.contactName || '',
partyBContactName: partyB.contactName || '',
partyCContactName: partyC.contactName || '',
partyAContactPhone: partyA.contactPhone || '',
partyBContactPhone: partyB.contactPhone || '',
partyCContactPhone: partyC.contactPhone || '',
partyAAddress: partyA.registeredAddress || partyA.contactAddress || '',
partyBAddress: partyB.registeredAddress || partyB.contactAddress || '',
partyCAddress: partyC.registeredAddress || partyC.contactAddress || '',
partyACreditCode: partyA.creditCode || '',
partyBCreditCode: partyB.creditCode || '',
partyCCreditCode: partyC.creditCode || '',
partyABankName: partyA.bankName || '',
partyBBankName: partyB.bankName || '',
partyCBankName: partyC.bankName || '',
partyABankAccount: partyA.bankAccount || '',
partyBBankAccount: partyB.bankAccount || '',
partyCBankAccount: partyC.bankAccount || '',
}
}
@@ -536,6 +781,11 @@ function buildContractSubmitPayload(formData, extra = {}) {
contractPeriodType: form.contractPeriodType,
periodExplain: form.periodExplain,
paymentMethod: form.paymentMethod,
paymentDirection: form.paymentDirection,
isElectron: form.isElectron,
textSource: form.textSource,
contractSource: form.contractSource,
dateType: form.dateType,
valuationMode: form.valuationMode,
currencyName: form.currencyName,
sealType: form.sealType,
@@ -543,8 +793,15 @@ function buildContractSubmitPayload(formData, extra = {}) {
cargoType: form.cargoType,
primaryContent: form.primaryContent,
amountExplain: form.amountExplain,
contractGistRemark: form.contractGistRemark,
bodySummary: form.bodySummary,
assistDept: form.assistDept,
executorAccount: form.executorAccount,
selfCode: form.selfCode,
mainContractCode: form.mainContractCode,
signingSubjectCode: form.signingSubjectCode,
invoiceDate: form.invoiceDate,
receiveDate: form.receiveDate,
},
partyMaintenance: {
isThreePartyContract: form.partyState.isThreePartyContract ? 1 : 0,
@@ -557,16 +814,29 @@ function buildContractSubmitPayload(formData, extra = {}) {
startTime: form.effectiveStart,
endTime: form.effectiveEnd,
periodExplain: form.periodExplain,
dateType: form.dateType,
valuationMode: form.valuationMode,
currencyName: form.currencyName,
sealType: form.sealType,
isText: form.textSource,
isElectron: form.isElectron,
paymentDirection: form.paymentDirection,
primaryContent: form.primaryContent,
amountExplain: form.amountExplain,
contractGistRemark: form.contractGistRemark,
isMajorContract: form.isMajorContract ? 1 : 0,
contractOpposites: buildContractOpposites(form.partyState),
otherAttach: form.otherAttachmentList.map((item) => ({
fileName: item.name,
fileSize: item.size,
fileName: item.name || item.fileName,
filePath: item.filePath,
fileType: item.fileType,
fileSize: item.size ?? item.fileSize,
})),
contractGistFile: form.contractGistFileList.map((item) => ({
fileName: item.name || item.fileName,
filePath: item.filePath,
fileType: item.fileType,
fileSize: item.size ?? item.fileSize,
})),
contractBodyFileName: form.contractBodyFileName,
performancePlans: form.performancePlans,
@@ -639,14 +909,21 @@ const launchFieldList = computed(() => {
return fieldKeys.map((key) => ({
key,
label: templateFieldLabelMap.value[key] || key,
readonly: Object.prototype.hasOwnProperty.call(templateVariables.value, key),
}));
});
function getLaunchFieldValue(fieldKey) {
if (Object.prototype.hasOwnProperty.call(templateVariables.value, fieldKey)) {
return templateVariables.value[fieldKey] ?? "";
}
return contractDetailState.value[fieldKey] ?? "";
}
function setLaunchFieldValue(fieldKey, value) {
if (Object.prototype.hasOwnProperty.call(templateVariables.value, fieldKey)) {
return;
}
contractDetailState.value[fieldKey] = value;
}
@@ -713,7 +990,11 @@ watch(
if (mode === "template" && prevMode === "manual") {
contractDetailState.value.contractBodyFileName = "";
contractDetailState.value.contractBodyFilePath = "";
contractDetailState.value.contractBodyFileType = "";
contractDetailState.value.contractBodyFileSize = null;
contractDetailState.value.contractBodyArrayBuffer = null;
contractDetailState.value.textSource = "standardText";
syncManualBodyFileList();
}
@@ -846,7 +1127,10 @@ async function buildFilledDocumentBlob() {
if (mappings.length) {
mappings.forEach((item) => {
if (!item.variableKey) return;
renderData[item.variableKey] = sourceValues[item.bindField] ?? "";
renderData[item.variableKey] =
sourceValues[item.bindField] ??
contractDetailState.value[item.bindField] ??
"";
});
} else {
Object.assign(renderData, sourceValues);
@@ -930,7 +1214,20 @@ async function handleManualContractBodyUpload(file) {
return false;
}
const formData = new FormData();
formData.append("file", file);
const uploadRes = await uploadLaunchFile(formData);
if (String(uploadRes?.code || "") !== "0000" || !uploadRes?.result) {
message.error(uploadRes?.message || uploadRes?.msg || "合同正文上传失败");
return false;
}
contractDetailState.value.contractBodyFileName = file.name;
contractDetailState.value.contractBodyFilePath = uploadRes.result;
contractDetailState.value.contractBodyFileType =
file.name.split(".").pop()?.toLowerCase() || "docx";
contractDetailState.value.contractBodyFileSize = file.size;
contractDetailState.value.textSource = "draftBySelf";
contractDetailState.value.contractBodyArrayBuffer = await readFileAsArrayBuffer(
file,
);
@@ -944,6 +1241,9 @@ async function handleManualContractBodyUpload(file) {
function handleRemoveManualContractBody() {
contractDetailState.value.contractBodyFileName = "";
contractDetailState.value.contractBodyFilePath = "";
contractDetailState.value.contractBodyFileType = "";
contractDetailState.value.contractBodyFileSize = null;
contractDetailState.value.contractBodyArrayBuffer = null;
syncManualBodyFileList();
previewBlob.value = null;
@@ -952,11 +1252,38 @@ function handleRemoveManualContractBody() {
return true;
}
async function uploadBlobAsLaunchFile(blob, fileName) {
const file = new File([blob], fileName, {
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
const formData = new FormData();
formData.append("file", file);
const uploadRes = await uploadLaunchFile(formData);
if (String(uploadRes?.code || "") !== "0000" || !uploadRes?.result) {
throw new Error(uploadRes?.message || uploadRes?.msg || "合同正文上传失败");
}
contractDetailState.value.contractBodyFileName = fileName;
contractDetailState.value.contractBodyFilePath = uploadRes.result;
contractDetailState.value.contractBodyFileType = "docx";
contractDetailState.value.contractBodyFileSize = file.size;
}
async function ensureTemplateBodyFileUploaded() {
if (creationMode.value !== "template") return;
const blob = previewBlob.value || (await buildFilledDocumentBlob());
previewBlob.value = blob;
const fileName = `${contractDetailState.value.contractName || "合同正文"}.docx`;
await uploadBlobAsLaunchFile(blob, fileName);
}
function validateMainForm() {
if (creationMode.value === "template" && !templateKey.value)
return "请选择合同模板";
for (const field of launchFieldList.value) {
if (field.readonly) {
continue;
}
const value = getLaunchFieldValue(field.key);
if (value === null || value === undefined || value === "") {
return `请输入${field.label}`;
@@ -971,21 +1298,26 @@ function validateMainForm() {
return "";
}
function handleSave() {
async function handleSave() {
const errorMessage = validateMainForm();
if (errorMessage) {
message.warning(errorMessage);
return;
}
emit("save", {
creationMode: creationMode.value,
templateKey: templateKey.value,
templateName: activeTemplate.value?.templateName || "",
detailState: copyContractFormData(contractDetailState.value),
});
visible.value = false;
message.success("合同正文配置已保存");
try {
await ensureTemplateBodyFileUploaded();
emit("save", {
creationMode: creationMode.value,
templateKey: templateKey.value,
templateName: activeTemplate.value?.templateName || "",
detailState: copyContractFormData(contractDetailState.value),
});
visible.value = false;
message.success("合同正文配置已保存");
} catch (error) {
message.warning(error?.message || "合同正文保存失败");
}
}
function resetForm() {