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.

993 lines
38 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" style="margin-top: 0">
<!-- <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.flowStatus"
:pageType="routeParams.type"
:mode="false"
/>
</el-card>
<el-card shadow="never" style="margin-top: 0">
<el-form ref="contractInfoFormRef" :model="form" :loading="buttonLoading" :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" :disabled="isFormDisabled">
<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">
<el-input v-model="form.contractCode" placeholder="请输入合同编号" :disabled="isFormDisabled">
<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="请输入合同名称" :disabled="isFormDisabled" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同大类" prop="contractCategory">
<el-select v-model="form.contractCategory" placeholder="请选择合同大类" disabled>
<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="请选择业务方向" :disabled="isFormDisabled">
<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" :disabled="isFormDisabled" 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"
:disabled="isFormDisabled"
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="oneCustomerId">
<el-select v-model="form.oneCustomerId" placeholder="请选择甲方公司" :disabled="isFormDisabled" 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="请选择乙方公司" :disabled="isFormDisabled" 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="请输入甲方授权代表" :disabled="isFormDisabled" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="乙方授权代表" prop="twoRepresent">
<el-input v-model="form.twoRepresent" placeholder="请输入乙方授权代表" :disabled="isFormDisabled" />
</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="请选择甲方签字日期"
:disabled="isFormDisabled"
>
</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="请选择乙方签字日期"
:disabled="isFormDisabled"
>
</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="contractTemplateFlag">
<el-radio-group v-model="form.contractTemplateFlag" :disabled="isFormDisabled">
<el-radio v-for="dict in contract_template_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="contractManagerId">
<el-select v-model="form.contractManagerId" placeholder="请选择该合同客户经理或签订人" :disabled="isFormDisabled" filterable>
<el-option v-for="item in userInfoList" :key="item.userId" :label="item.nickName" :value="item.userId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合同模板" prop="templateId" v-if="form.contractTemplateFlag !== '1'">
<el-select v-model="form.templateId" placeholder="请选择合同模板" :disabled="isFormDisabled" 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="capitalizedAmount">
<el-input v-model="form.capitalizedAmount" placeholder="请输入合同大写金额" />
</el-form-item>
</el-col> -->
<el-col :span="12">
<el-form-item label="附件" prop="ossId">
<!-- <el-button type="primary" plain icon="Upload" @click="handleFile">上传合同附件</el-button>-->
<FileUpload
v-model="ossIdString"
:limit="5"
:fileSize="20"
:fileType="['doc', 'docx', 'pdf', 'xls', 'xlsx']"
:disabled="isFormDisabled"
:isShowTip="true"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" :disabled="isFormDisabled" />
</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-row>
</el-form>
</el-card>
<!-- 合同物料区域 -->
<el-card shadow="never" style="margin-top: 0">
<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" v-if="routeParams.type !== 'view' && routeParams.type != 'approval'" @click="handleAddMaterial"
>新增物料
</el-button>
</div>
<el-table :data="contractMaterialList" v-loading="buttonLoading" border>
<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="物料编号" align="center" prop="materialCode" width="120" />
<el-table-column label="物料名称" align="center" prop="materialName" width="120" />
<el-table-column label="销售物料名称" align="center" prop="saleMaterialName" width="120" />
<el-table-column label="数量" align="center" prop="amount" width="80">
<template #default="scope">
{{ scope.row.amount ? Number(scope.row.amount).toFixed(2) : '0.00' }}
</template>
</el-table-column>
<el-table-column label="单位" align="center" prop="unitName" width="60" />
<el-table-column label="未税单价" align="center" prop="beforePrice" width="100">
<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="80">
<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="100">
<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="80">
<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" v-if="routeParams.type !== 'view' && routeParams.type != 'approval'">
<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>
<!-- 合同物料编辑对话框 -->
<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="materialFlag">
<el-radio-group v-model="materialForm.materialFlag">
<el-radio v-for="dict in material_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.materialFlag === '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.materialFlag === '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.materialFlag === '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-select
v-model="materialForm.taxRate"
placeholder="请选择或输入税率"
style="width: 100%"
@change="calculateBeforePrice"
filterable
allow-create
default-first-option
>
<el-option label="6" :value="6"></el-option>
<el-option label="13" :value="13"></el-option>
</el-select>
</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 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, contractSubmitAndFlowStart, getContractInfo, updateContractInfo } from '@/api/oa/erp/contractInfo';
import { ContractInfoForm } from '@/api/oa/erp/contractInfo/types';
import { ContractMaterialVO, ContractMaterialForm } from '@/api/oa/erp/contractMaterial/types';
import { getBaseUnitInfoList } from '@/api/oa/base/unitInfo';
import { getRuleGenerateCode } from '@/api/system/codeRule';
import { startWorkFlow } from '@/api/workflow/task';
import { StartProcessBo } from '@/api/workflow/workflowCommon/types';
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 { allListDept, listDept } from '@/api/system/dept';
import { getCrmCustomerInfoList } from '@/api/oa/crm/customerInfo';
import { getBasePrintTemplateList } from '@/api/oa/base/printTemplate';
import { getUserList } from '@/api/system/user';
import { CodeRuleEnum, FlowCodeEnum } from '@/enums/OAEnum';
import { getInfo } from '@/api/login';
import FileUpload from '@/components/FileUpload/index.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute();
const router = useRouter();
//
const routeParams = ref<Record<string, any>>({});
const { contract_category, business_direction, contract_flag, contract_type, contract_status, material_flag, contract_template_flag } = toRefs<any>(
proxy?.useDict('contract_category', 'business_direction', 'contract_flag', 'contract_type', 'contract_status', 'material_flag', 'contract_template_flag')
);
const buttonLoading = ref(false);
const contractInfoFormRef = ref<ElFormInstance>();
// 审批相关组件引用
const submitVerifyRef = ref<InstanceType<typeof SubmitVerify>>();
const approvalRecordRef = ref<InstanceType<typeof ApprovalRecord>>();
// 流程相关数据
const submitFormData = ref<StartProcessBo>({
businessId: '',
flowCode: '',
variables: {},
bizExt: {}
});
// 任务变量
const taskVariables = ref<Record<string, any>>({});
const flowInstanceBizExtBo = 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 materialFormRef = ref<ElFormInstance>();
// 合同物料列表计算属性
const contractMaterialList = computed(() => {
return (form.value as any).contractMaterialList || [];
});
/** 查询打印模板下拉框结构 */
const printTemplateList = ref([]);
const getPrintTemplateListSelect = async () => {
const res = await getBasePrintTemplateList({ templateType: '1' });
printTemplateList.value = res.data;
};
/** 查询单位信息下拉框结构 */
const unitInfoList = ref([]);
const getUnitInfoListSelect = async () => {
const res = await getBaseUnitInfoList(null);
unitInfoList.value = res.data;
};
/** 查询部门信息下拉框结构 */
const deptInfoList = ref([]);
const getDeptInfoListSelect = async () => {
const params = { deptCategory: '03' } as any;
const res = await allListDept(params);
deptInfoList.value = res.data;
};
/** 查询客户信息下拉框结构 */
const customerInfoList = ref([]);
const getCustomerInfoListSelect = async () => {
const res = await getCrmCustomerInfoList(null);
customerInfoList.value = res.data;
};
/** 查询用户信息下拉框结构 */
const userInfoList = ref([]);
const getUserInfoListSelect = async () => {
const res = await getUserList({ pageNum: 1, pageSize: 1000 });
userInfoList.value = res.data;
};
// 合同物料对话框
const materialDialog = reactive({
visible: false,
title: ''
});
// 合同物料表单数据
const initMaterialFormData: ContractMaterialForm = {
contractMaterialId: undefined,
materialFlag: '2',
contractId: undefined,
productName: undefined,
specificationDescription: undefined,
materialId: undefined,
relationMaterialId: undefined,
saleMaterialName: 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,
contractManagerId: undefined,
capitalizedAmount: undefined,
contractTemplateFlag: '2',
flowCode: undefined,
bizExt: undefined,
variables: undefined,
activeFlag: '1',
contractMaterialList: [],
file: undefined
} as any;
const data = reactive<{ form: ContractInfoFormEx; rules: any }>({
form: { ...initFormData },
rules: {
contractFlag: [{ required: true, message: '有无合同不能为空', trigger: 'blur' }],
contractCode: [{ required: true, message: '合同编号不能为空', trigger: 'blur' }],
contractName: [{ required: true, message: '合同名称不能为空', trigger: 'blur' }],
businessDirection: [{ required: true, message: '业务方向不能为空', trigger: 'blur' }],
contractManagerId: [{ required: true, message: '合同负责人不能为空', trigger: 'blur' }],
contractDeptId: [{ required: true, message: '部门不能为空', trigger: 'blur' }],
contractTemplateFlag: [{ required: true, message: '合同模板标识不能为空', trigger: 'blur' }],
}
});
// 判断表单是否禁用(查看或审批模式)
const isFormDisabled = computed(() => {
return routeParams.value.type === 'view' || routeParams.value.type === 'approval';
});
// 附件ID字符串转换用于FileUpload组件
const ossIdString = computed({
get() {
const v = form.value.ossId as any;
return v === undefined || v === null ? '' : String(v);
},
set(val: string) {
form.value.ossId = val || (undefined as any);
}
});
const { form, rules } = toRefs(data);
// 监听contractFlag变化
watch(
() => form.value.contractFlag,
(newVal) => {
if (newVal === '2') {
// 当选择"无合同"时,清空合同编号并重置生成状态
form.value.contractCode = undefined;
isCodeGenerated.value = false;
}
}
);
// 生成合同编号
const generateContractCode = async () => {
if (isCodeGenerated.value) return; // 如果已经生成过,直接返回
try {
const params = { codeRuleCode: CodeRuleEnum.CONTRACT } 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: any) => {
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.saleMaterialName = 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) => {
try {
buttonLoading.value = true;
contractInfoFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
// 设置后端发起和不等于草稿状态 直接走流程发起
if (status != 'draft') {
// 后端发起流程模式
form.value.flowCode = FlowCodeEnum.CONTRACT_CODE;
// 流程变量
form.value.variables = {
contractName: form.value.contractName,
totalPrice: form.value.totalPrice,
businessDirection: form.value.businessDirection,
contractDeptId: form.value.contractDeptId,
contractCode: form.value.contractCode
};
// 流程实例业务扩展字段
form.value.bizExt = {
businessTitle: '合同审批',
businessCode: form.value.contractCode
};
form.value.contractStatus = '2';
form.value.flowStatus = 'waiting';
const res = await contractSubmitAndFlowStart(form.value).finally(() => (buttonLoading.value = false));
form.value = res.data;
proxy?.$modal.msgSuccess('操作成功');
proxy?.$tab.closePage();
router.go(-1);
} else {
if (status === 'draft') {
form.value.contractStatus = '1';
form.value.flowStatus = 'draft';
}
if (form.value.contractId) {
await updateContractInfo(form.value).finally(() => (buttonLoading.value = false));
} else {
await addContractInfo(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('暂存成功');
proxy?.$tab.closePage();
router.go(-1);
}
}
});
} finally {
buttonLoading.value = false;
}
};
// 提交申请
const handleStartWorkFlow = async (data: ContractInfoForm) => {
try {
submitFormData.value.flowCode = FlowCodeEnum.CONTRACT_CODE;
submitFormData.value.businessId = data.contractId;
// 流程变量
taskVariables.value = {
contractId: data.contractId,
contractName: data.contractName,
totalPrice: data.totalPrice,
businessDirection: data.businessDirection,
contractDeptId: data.contractDeptId,
contractCode: data.contractCode
};
// 流程实例业务扩展字段
flowInstanceBizExtBo.value = {
businessTitle: '合同审批',
businessCode: data.contractCode
};
submitFormData.value.variables = taskVariables.value;
submitFormData.value.bizExt = flowInstanceBizExtBo.value;
const resp = await startWorkFlow(submitFormData.value);
if (submitVerifyRef.value) {
buttonLoading.value = false;
await submitVerifyRef.value.openDialog(resp.data.taskId);
}
} finally {
buttonLoading.value = false;
router.go(-1);
}
};
// 确认上传,仅关闭弹窗并依赖 v-model 同步到 ossId
const submitOss = () => {
// 将上传组件返回的 ossId 串写回表单
form.value.ossId = ossFileModel.value as any;
dialog.visible = false;
proxy?.$modal.msgSuccess('附件已更新');
};
// 新增物料新增合同时也可添加不依赖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) {
// 确保contractMaterialList存在
if (!(form.value as any).contractMaterialList) {
(form.value as any).contractMaterialList = [];
}
const unitInfo = unitInfoList.value.find((item: any) => item.unitId === materialForm.value.unitId);
const unitName = unitInfo ? unitInfo.unitName : '';
const materialData = {
...materialForm.value,
unitName: unitName
};
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] = materialData;
}
} else {
// 新增模式:添加新物料
const newMaterial = {
...materialData,
contractMaterialId: Date.now() // 临时ID
};
(form.value as any).contractMaterialList.push(newMaterial);
}
// 更新合同总价
calculateTotalPrice();
proxy?.$modal.msgSuccess('操作成功');
materialDialog.visible = false;
}
});
};
//初始化调用
const loadSelectOptions = () => {
getUnitInfoListSelect();
getDeptInfoListSelect();
getCustomerInfoListSelect();
getPrintTemplateListSelect();
getUserInfoListSelect();
};
onMounted(async () => {
nextTick(async () => {
// 获取路由参数
routeParams.value = route.query;
loadSelectOptions();
const id = routeParams.value.id as string | number;
if (id && (routeParams.value.type === 'update' || routeParams.value.type === 'view' || routeParams.value.type === 'approval')) {
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;
}
} else {
try {
// 新增模式获取登录用户部门ID并自动赋值
// const userInfoRes = await getInfo();
// if (userInfoRes.data?.user?.deptId && !form.value.contractDeptId) {
// form.value.contractDeptId = userInfoRes.data.user.deptId;
// }
form.value.contractCategory = routeParams.value.contractCategory as string;
} catch (error) {
console.error('获取用户信息失败:', error);
}
// 新增模式:如果已有合同编号,禁用生成按钮
if (form.value.contractCode) {
isCodeGenerated.value = true;
} else if (form.value.contractFlag === '1') {
// 如果有合同但没有编号,允许生成
isCodeGenerated.value = false;
}
}
});
});
// 审批记录
const handleApprovalRecord = () => {
approvalRecordRef.value.init(form.value.contractId);
};
// 提交回调
const submitCallback = async () => {
await proxy.$tab.closePage(route);
router.go(-1);
};
// 审批
const approvalVerifyOpen = async () => {
await submitVerifyRef.value.openDialog(routeParams.value.taskId);
};
// 监听上传组件返回的文件ossId 串)并同步到表单字段
// 同步表单初值到上传模型
watch(
() => form.value.ossId,
(val) => {
if (!dialog.visible) {
ossFileModel.value = val as any;
}
}
);
</script>