You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

871 lines
32 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="p-2">
<el-card shadow="never">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 24px">合同{{ form.contractId ? ' - 修改' : ' - 新增' }}</div>
</template>
<!-- 审批按钮组件 -->
<approvalButton
@submitForm="submitForm"
@approvalVerifyOpen="approvalVerifyOpen"
@handleApprovalRecord="handleApprovalRecord"
:buttonLoading="buttonLoading"
:id="form.contractId"
:status="form.contractStatus"
:pageType="routeParams.type"
:mode="false"
/>
<el-form ref="contractInfoFormRef" :model="form" :rules="rules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="有无合同" prop="contractFlag">
<el-radio-group v-model="form.contractFlag">
<el-radio v-for="dict in contract_flag" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同编号" prop="contractCode" v-if="form.contractFlag === '1'">
<el-input v-model="form.contractCode" placeholder="请输入合同编号">
<template #append>
<el-button type="primary" @click="generateContractCode" :disabled="isCodeGenerated">生成合同编号 </el-button>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同名称" prop="contractName">
<el-input v-model="form.contractName" placeholder="请输入合同名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同大类" prop="contractCategory">
<el-select v-model="form.contractCategory" placeholder="请选择合同大类">
<el-option v-for="dict in contract_category" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同类型" prop="contractType">
<el-select v-model="form.contractType" placeholder="请选择合同类型">
<el-option v-for="dict in contract_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="业务方向" prop="businessDirection">
<el-select v-model="form.businessDirection" placeholder="请选择业务方向">
<el-option v-for="dict in business_direction" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="部门" prop="contractDeptId">
<el-select v-model="form.contractDeptId" placeholder="请选择部门">
<el-option v-for="item in deptInfoList" :key="item.deptId" :label="item.deptName" :value="item.deptId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同时间" prop="contractDate">
<el-date-picker clearable v-model="form.contractDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择合同时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同总价" prop="totalPrice">
<el-input v-model="form.totalPrice" placeholder="根据合同物料自动计算" disabled>
<template #append>元</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="付款方式" prop="paymentMethod">
<el-input v-model="form.paymentMethod" placeholder="3-3-3-1" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="甲方公司" prop="oneCustomerId">
<el-select v-model="form.oneCustomerId" placeholder="请选择甲方公司" filterable>
<el-option v-for="item in customerInfoList" :key="item.customerId" :label="item.customerName" :value="item.customerId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="乙方公司" prop="twoCustomerId">
<el-select v-model="form.twoCustomerId" placeholder="请选择乙方公司" filterable>
<el-option v-for="item in customerInfoList" :key="item.customerId" :label="item.customerName" :value="item.customerId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="甲方授权代表" prop="oneRepresent">
<el-input v-model="form.oneRepresent" placeholder="请输入甲方授权代表" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="乙方授权代表" prop="twoRepresent">
<el-input v-model="form.twoRepresent" placeholder="请输入乙方授权代表" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="甲方签字日期" prop="oneDate">
<el-date-picker clearable v-model="form.oneDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择甲方签字日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="乙方签字日期" prop="twoDate">
<el-date-picker clearable v-model="form.twoDate" type="date" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择乙方签字日期">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同状态" prop="contractStatus">
<el-radio-group v-model="form.contractStatus" disabled>
<el-radio v-for="dict in contract_status" :key="dict.value" :value="dict.value">{{ dict.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<!-- <el-col :span="12">-->
<!-- <el-form-item label="流程状态" prop="flowStatus">-->
<!-- <el-input v-model="form.flowStatus" placeholder="请输入流程状态" />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="12">
<el-form-item label="合同模板" prop="templateId">
<el-select v-model="form.templateId" placeholder="请选择合同模板" filterable>
<el-option
v-for="item in printTemplateList"
:key="item.templateId"
:label="item.templateName + '-' + item.version"
:value="item.templateId"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="附件" prop="ossId">
<!-- <el-input v-model="form.ossId" type="textarea" placeholder="请输入内容" />-->
<el-button type="primary" plain icon="Upload" @click="handleFile">上传合同附件</el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 合同物料管理区域 -->
<el-card shadow="never" style="margin-top: 20px">
<template #header>
<div style="text-align: left; font-weight: bold; font-size: 18px">合同物料管理</div>
</template>
<!-- 合同物料表格 -->
<div style="margin-bottom: 16px">
<el-button type="primary" icon="Plus" @click="handleAddMaterial">新增物料</el-button>
</div>
<el-table :data="contractMaterialList" border v-loading="materialLoading">
<el-table-column label="产品名称" align="center" prop="productName" min-width="120" />
<el-table-column label="规格描述" align="center" prop="specificationDescription" min-width="120" />
<el-table-column label="物料ID" align="center" prop="materialId" width="100" />
<el-table-column label="销售物料ID" align="center" prop="relationMaterialId" width="120" />
<el-table-column label="数量" align="center" prop="amount" width="100">
<template #default="scope">
{{ scope.row.amount ? Number(scope.row.amount).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="单位ID" align="center" prop="unitId" width="100" />
<el-table-column label="未税单价" align="center" prop="beforePrice" width="120">
<template #default="scope">
{{ scope.row.beforePrice ? Number(scope.row.beforePrice).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="税率(%)" align="center" prop="taxRate" width="100">
<template #default="scope">
{{ scope.row.taxRate ? Number(scope.row.taxRate).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="含税单价" align="center" prop="includingPrice" width="120">
<template #default="scope">
{{ scope.row.includingPrice ? Number(scope.row.includingPrice).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="小计" align="center" prop="subtotal" width="120">
<template #default="scope">
{{ scope.row.subtotal ? Number(scope.row.subtotal).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="100" />
<el-table-column label="操作" align="center" fixed="right" width="150">
<template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleEditMaterial(scope.row)">编辑</el-button>
<el-button link type="danger" icon="Delete" @click="handleDeleteMaterial(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-card shadow="never" style="margin-top: 20px" v-if="routeParams.type !== 'approval'">
<el-col :span="24">
<el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="() => submitForm('draft', false)">保 存</el-button>
<el-button @click="goBack">返 回</el-button>
</el-form-item>
</el-col>
</el-card>
</el-card>
<!-- 合同物料编辑对话框 -->
<el-dialog :title="materialDialog.title" v-model="materialDialog.visible" width="800px" append-to-body>
<el-form ref="materialFormRef" :model="materialForm" :rules="materialRules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="计划标识" prop="planFlag">
<el-radio-group v-model="materialForm.planFlag">
<el-radio v-for="dict in plan_flag" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料名称" prop="materialName" v-if="materialForm.planFlag === '1'">
<el-input v-model="materialForm.materialName" placeholder="计划内请点击右侧图标检索物料">
<template #suffix>
<el-icon style="cursor: pointer" @click="openSaleMaterialSelect">
<Search />
</el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料编号" prop="materialCode" v-if="materialForm.planFlag === '1'">
<el-input v-model="materialForm.materialCode" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="客户名称" prop="customerName" v-if="materialForm.planFlag === '1'">
<el-input v-model="materialForm.customerName" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产品名称" prop="productName">
<el-input v-model="materialForm.productName" placeholder="请输入产品名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="规格描述" prop="specificationDescription">
<el-input v-model="materialForm.specificationDescription" placeholder="请输入规格描述" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="数量" prop="amount">
<el-input-number
v-model="materialForm.amount"
placeholder="请输入数量"
style="width: 100%"
@change="calculateSubtotal"
:precision="2"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料单位" prop="unitId">
<el-select v-model="materialForm.unitId" placeholder="请选择物料单位">
<el-option v-for="item in unitInfoList" :key="item.unitId" :label="item.unitName" :value="item.unitId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="税率(%)" prop="taxRate">
<el-input-number
v-model="materialForm.taxRate"
placeholder="请输入税率"
style="width: 100%"
@change="calculateBeforePrice"
:precision="2"
:min="0"
:max="100"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="未税单价" prop="beforePrice">
<el-input-number
v-model="materialForm.beforePrice"
placeholder="自动计算"
style="width: 100%"
:precision="2"
:controls="false"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="含税单价" prop="includingPrice">
<el-input-number
v-model="materialForm.includingPrice"
placeholder="请输入含税单价"
style="width: 100%"
:precision="2"
@change="calculateBeforePrice"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="小计" prop="subtotal">
<el-input-number
v-model="materialForm.subtotal"
placeholder="自动计算"
style="width: 100%"
readonly
:precision="2"
:controls="false"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="materialForm.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="materialButtonLoading" type="primary" @click="submitMaterialForm">确 定</el-button>
<el-button @click="cancelMaterial">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 销售物料选择 -->
<SaleMaterialSelect ref="saleMaterialSelectRef" :multiple="false" @confirm-call-back="saleMaterialSelectCallBack"></SaleMaterialSelect>
<!-- 添加或修改OSS对象存储对话框 -->
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
<el-form ref="ossFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文件名">
<fileUpload v-if="type === 0" v-model="ossFileModel" />
<imageUpload v-if="type === 1" v-model="ossFileModel" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitOss">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 提交审批组件 -->
<submitVerify ref="submitVerifyRef" :task-variables="taskVariables" @submit-callback="submitCallback" />
<!-- 审批记录 -->
<approvalRecord ref="approvalRecordRef" />
</div>
</template>
<script setup name="ContractInfoEdit" lang="ts">
import { addContractInfo, getContractInfo, updateContractInfo } from '@/api/oa/erp/contractInfo';
import { ContractInfoForm } from '@/api/oa/erp/contractInfo/types';
import { getErpContractMaterialList } from '@/api/oa/erp/contractMaterial';
import { ContractMaterialVO, ContractMaterialForm } from '@/api/oa/erp/contractMaterial/types';
import { getBaseUnitInfoList } from '@/api/oa/base/unitInfo';
import { getRuleGenerateCode } from '@/api/system/codeRule';
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 { ref } from 'vue';
import { listDept } from '@/api/system/dept';
import { getCrmCustomerInfoList } from '@/api/oa/crm/customerInfo';
import { getBasePrintTemplateList } from '@/api/oa/base/printTemplate';
const route = useRoute();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
//
const routeParams = ref<Record<string, any>>({});
const { contract_category, business_direction, active_flag, contract_flag, contract_type, contract_status, plan_flag } = toRefs<any>(
proxy?.useDict('contract_category', 'business_direction', 'active_flag', 'contract_flag', 'contract_type', 'contract_status', 'plan_flag')
);
const buttonLoading = ref(false);
const contractInfoFormRef = ref<ElFormInstance>();
// 审批相关组件引用
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
// 任务变量
const taskVariables = ref<Record<string, any>>({});
const type = ref(0);
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
// OSS 上传内部 v-model 中转,避免直接绑定到 form 的未知属性
const ossFileModel = ref<string | string[] | undefined>(undefined);
// 合同编号生成状态
const isCodeGenerated = ref(false);
// 合同物料相关
const materialLoading = ref(false);
const materialButtonLoading = ref(false);
const materialFormRef = ref<ElFormInstance>();
// 合同物料列表计算属性
const contractMaterialList = computed(() => {
return (form.value as any).contractMaterialList || [];
});
/** 查询打印模板下拉框结构 */
const printTemplateList = ref([]);
const getPrintTemplateListSelect = async () => {
let res = await getBasePrintTemplateList(null);
printTemplateList.value = res.data;
};
/** 查询单位信息下拉框结构 */
const unitInfoList = ref([]);
const getUnitInfoListSelect = async () => {
let res = await getBaseUnitInfoList(null);
unitInfoList.value = res.data;
};
/** 查询部门信息下拉框结构 */
const deptInfoList = ref([]);
const getDeptInfoListSelect = async () => {
const params = { deptCategory: '03' } as any;
let res = await listDept(params);
deptInfoList.value = res.data;
};
/** 查询客户信息下拉框结构 */
const customerInfoList = ref([]);
const getCustomerInfoListSelect = async () => {
let res = await getCrmCustomerInfoList(null);
customerInfoList.value = res.data;
};
// 合同物料对话框
const materialDialog = reactive({
visible: false,
title: ''
});
// 合同物料表单数据
const initMaterialFormData: ContractMaterialForm = {
contractMaterialId: undefined,
planFlag: '2',
contractId: undefined,
productName: undefined,
specificationDescription: undefined,
materialId: undefined,
relationMaterialId: undefined,
amount: undefined,
unitId: undefined,
beforePrice: undefined,
taxRate: undefined,
includingPrice: undefined,
subtotal: undefined,
remark: undefined,
activeFlag: '1'
};
const materialForm = ref<ContractMaterialForm>({ ...initMaterialFormData });
// 合同物料表单验证规则
const materialRules = {
productName: [{ required: true, message: '产品名称不能为空', trigger: 'blur' }],
amount: [{ required: true, message: '数量不能为空', trigger: 'blur' }],
taxRate: [{ required: true, message: '税率不能为空', trigger: 'blur' }]
};
type ContractInfoFormEx = ContractInfoForm & { file?: any };
const initFormData: ContractInfoFormEx = {
contractId: undefined,
contractFlag: '1',
contractCode: undefined,
contractName: undefined,
contractCategory: '1',
contractType: undefined,
businessDirection: undefined,
contractDeptId: undefined,
contractDate: undefined,
totalPrice: 0,
oneCustomerId: undefined,
oneRepresent: undefined,
oneDate: undefined,
twoCustomerId: undefined,
twoRepresent: undefined,
twoDate: undefined,
contractStatus: '1',
flowStatus: undefined,
templateId: undefined,
ossId: undefined,
paymentMethod: undefined,
signatureAppendix: undefined,
taxRate: undefined,
remark: undefined,
activeFlag: '1',
contractMaterialList: [],
file: undefined
} as any;
const data = reactive<{ form: ContractInfoFormEx; rules: any }>({
form: { ...initFormData },
rules: {
contractId: [{ required: true, message: '合同ID不能为空', trigger: 'blur' }]
}
});
const { form, rules } = toRefs(data);
const goBack = () => {
proxy?.$tab.closePage();
};
// 监听contractFlag变化
watch(
() => form.value.contractFlag,
(newVal, oldVal) => {
if (newVal === '2') {
// 当选择"无合同"时,清空合同编号并重置生成状态
form.value.contractCode = undefined;
isCodeGenerated.value = false;
}
}
);
// 生成合同编号
const generateContractCode = async () => {
if (isCodeGenerated.value) return; // 如果已经生成过,直接返回
try {
const params = { codeRuleCode: '1001' } as any;
const res = await getRuleGenerateCode(params);
form.value.contractCode = res.msg;
isCodeGenerated.value = true; // 标记为已生成
proxy?.$modal.msgSuccess('合同编号生成成功');
} catch (error) {
console.error('生成合同编号失败:', error);
proxy?.$modal.msgError('生成合同编号失败');
}
};
const saleMaterialSelectRef = ref<InstanceType<typeof SaleMaterialSelect>>();
//打开销售物料选择
const openSaleMaterialSelect = () => {
saleMaterialSelectRef.value.open();
};
//确认选择申请人
const saleMaterialSelectCallBack = (data) => {
const materialList = data;
if (materialList.length > 0) {
materialForm.value.materialId = materialList[0].materialId;
materialForm.value.materialCode = materialList[0].materialCode;
materialForm.value.materialName = materialList[0].materialName;
materialForm.value.productName = materialList[0].saleMaterialName;
materialForm.value.relationMaterialId = materialList[0].relationMaterialId;
materialForm.value.customerName = materialList[0].customerName;
}
};
/** 取消按钮 */
function cancel() {
dialog.visible = false;
}
/** 文件按钮操作 */
const handleFile = () => {
type.value = 0;
dialog.visible = true;
dialog.title = '上传合同附件';
// 打开时回显已有附件
ossFileModel.value = form.value.ossId as any;
};
const submitForm = (status: string, mode: boolean) => {
contractInfoFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
try {
if (form.value.contractId) {
await updateContractInfo(form.value).finally(() => (buttonLoading.value = false));
} else {
await addContractInfo(form.value).finally(() => (buttonLoading.value = false));
}
if (status === 'draft') {
proxy?.$modal.msgSuccess('暂存成功');
goBack();
} else {
// 提交审批流程
await handleStartWorkFlow();
}
} catch (error) {
console.error('保存合同信息失败:', error);
buttonLoading.value = false;
}
}
});
};
// 确认上传,仅关闭弹窗并依赖 v-model 同步到 ossId
const submitOss = () => {
// 将上传组件返回的 ossId 串写回表单
form.value.ossId = ossFileModel.value as any;
dialog.visible = false;
proxy?.$modal.msgSuccess('附件已更新');
};
// 获取合同物料列表
const getContractMaterialList = async () => {
if (!form.value.contractId) return;
materialLoading.value = true;
try {
const res = await getErpContractMaterialList({
contractId: form.value.contractId
});
// 将获取到的数据存储到form中
(form.value as any).contractMaterialList = res.data || [];
} catch (error) {
console.error('获取合同物料列表失败:', error);
} finally {
materialLoading.value = false;
}
};
// 新增物料新增合同时也可添加不依赖contractId
const handleAddMaterial = () => {
resetMaterialForm();
materialForm.value.contractId = form.value.contractId;
materialDialog.visible = true;
materialDialog.title = '新增合同物料';
};
// 编辑物料
const handleEditMaterial = (row: ContractMaterialVO) => {
resetMaterialForm();
materialForm.value = { ...row };
materialDialog.visible = true;
materialDialog.title = '编辑合同物料';
};
// 删除物料
const handleDeleteMaterial = async (row: ContractMaterialVO) => {
await proxy?.$modal.confirm('是否确认删除该合同物料?');
try {
// 确保contractMaterialList存在
if (!(form.value as any).contractMaterialList) {
(form.value as any).contractMaterialList = [];
}
// 从本地数据中删除
const index = (form.value as any).contractMaterialList.findIndex((item: any) => item.contractMaterialId === row.contractMaterialId);
if (index !== -1) {
(form.value as any).contractMaterialList.splice(index, 1);
}
// 更新合同总价
calculateTotalPrice();
proxy?.$modal.msgSuccess('删除成功');
} catch (error) {
console.error('删除合同物料失败:', error);
}
};
// 重置物料表单
const resetMaterialForm = () => {
materialForm.value = { ...initMaterialFormData };
materialFormRef.value?.resetFields();
};
// 取消物料编辑
const cancelMaterial = () => {
resetMaterialForm();
materialDialog.visible = false;
};
// 计算未税单价(由含税与税率推未税)
const calculateBeforePrice = () => {
const tax = Number(materialForm.value.taxRate);
const including = Number(materialForm.value.includingPrice);
if (!isNaN(tax) && !isNaN(including)) {
const divisor = 1 + tax / 100;
if (divisor > 0) {
materialForm.value.beforePrice = Number((including / divisor).toFixed(2));
}
}
// 未税变更后联动小计
calculateSubtotal();
};
// 计算小计(数量 × 含税单价)
const calculateSubtotal = () => {
const amount = Number(materialForm.value.amount);
const including = Number(materialForm.value.includingPrice);
if (!isNaN(amount) && !isNaN(including)) {
materialForm.value.subtotal = Number((amount * including).toFixed(2));
}
// 计算小计后更新合同总价
calculateTotalPrice();
};
// 计算合同总价(所有物料小计相加)
const calculateTotalPrice = () => {
const materialList = (form.value as any).contractMaterialList || [];
const total = materialList.reduce((sum: number, material: any) => {
const subtotal = Number(material.subtotal) || 0;
return sum + subtotal;
}, 0);
form.value.totalPrice = Number(total.toFixed(2));
};
// 提交物料表单
const submitMaterialForm = () => {
materialFormRef.value?.validate((valid: boolean) => {
if (valid) {
materialButtonLoading.value = true;
try {
// 确保contractMaterialList存在
if (!(form.value as any).contractMaterialList) {
(form.value as any).contractMaterialList = [];
}
if (materialForm.value.contractMaterialId) {
// 编辑模式:更新现有物料
const index = (form.value as any).contractMaterialList.findIndex(
(item: any) => item.contractMaterialId === materialForm.value.contractMaterialId
);
if (index !== -1) {
(form.value as any).contractMaterialList[index] = { ...materialForm.value };
}
} else {
// 新增模式:添加新物料
const newMaterial = {
...materialForm.value,
contractMaterialId: Date.now() // 临时ID
};
(form.value as any).contractMaterialList.push(newMaterial);
}
// 更新合同总价
calculateTotalPrice();
proxy?.$modal.msgSuccess('操作成功');
materialDialog.visible = false;
} catch (error) {
console.error('保存合同物料失败:', error);
} finally {
materialButtonLoading.value = false;
}
}
});
};
//初始化调用
const loadSelectOptions = () => {
getUnitInfoListSelect();
getDeptInfoListSelect();
getCustomerInfoListSelect();
getPrintTemplateListSelect();
};
onMounted(async () => {
// 获取路由参数
routeParams.value = route.query || {};
const id = (route.query.id || route.params.id) as string | number;
loadSelectOptions();
if (id) {
proxy?.$modal.loading('正在加载数据,请稍后...');
const res = await getContractInfo(id);
Object.assign(form.value, res.data);
proxy?.$modal.closeLoading();
// 编辑模式:如果已有合同编号,禁用生成按钮
if (form.value.contractCode) {
isCodeGenerated.value = true;
} else if (form.value.contractFlag === '1') {
// 如果有合同但没有编号,允许生成
isCodeGenerated.value = false;
}
// 加载合同物料列表
await getContractMaterialList();
} else {
// 新增模式:如果已有合同编号,禁用生成按钮
if (form.value.contractCode) {
isCodeGenerated.value = true;
} else if (form.value.contractFlag === '1') {
// 如果有合同但没有编号,允许生成
isCodeGenerated.value = false;
}
}
});
// 启动审批流程
const handleStartWorkFlow = async () => {
try {
// 设置流程变量
taskVariables.value = {
contractId: form.value.contractId,
contractName: form.value.contractName,
totalPrice: form.value.totalPrice,
contractCode: form.value.contractCode
};
// 这里可以根据需要调用启动流程的API
// 由于合同审批流程在index.vue中已经实现这里主要是处理审批中的状态
proxy?.$modal.msgSuccess('提交审批成功');
goBack();
} catch (error) {
console.error('启动审批流程失败:', error);
proxy?.$modal.msgError('启动审批流程失败');
}
};
// 审批验证打开
const approvalVerifyOpen = async () => {
if (submitVerifyRef.value && routeParams.value.taskId) {
submitVerifyRef.value.openDialog(routeParams.value.taskId);
}
};
// 查看审批记录
const handleApprovalRecord = () => {
if (approvalRecordRef.value && form.value.contractId) {
approvalRecordRef.value.init(form.value.contractId);
}
};
// 提交回调
const submitCallback = async () => {
await proxy?.$tab.closePage(route);
window.history.go(-1);
};
// 监听上传组件返回的文件ossId 串)并同步到表单字段
// 同步表单初值到上传模型
watch(
() => form.value.ossId,
(val) => {
if (!dialog.visible) {
ossFileModel.value = val as any;
}
}
);
</script>