Files
BMS/bms-front/src/views/customersuppliermanagement/supplierinfo/supplieredit/index.vue
T
2026-09-29 11:28:15 +08:00

1080 lines
44 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container supplier-edit-page" v-loading="pageLoading">
<!-- 顶部:返回 + 标题 + 保存 -->
<el-card shadow="never" class="head-card">
<div class="head-bar">
<el-button icon="ArrowLeft" @click="goBack">返回</el-button>
<div class="head-title">
<span class="supplier-name">{{ isAdd ? '新增供应商' : (form.supplierName || '-') }}</span>
<el-tag size="small" :type="isAdd ? 'warning' : 'info'">{{ isAdd ? '未保存' : '编辑中' }}</el-tag>
</div>
<div class="head-code">供应商编码:{{ form.supplierCode || '保存后可维护子表数据' }}</div>
<div class="head-right">
<el-button @click="goBack">取 消</el-button>
<el-button type="primary" :loading="saving" v-hasPermi="[isAdd ? 'customersupplier:supplierinfo:add' : 'customersupplier:supplierinfo:edit']" @click="submitForm">保 存</el-button>
</div>
</div>
</el-card>
<el-card shadow="never">
<el-tabs v-model="activeTab">
<!-- ============ 基本信息 ============ -->
<el-tab-pane label="基本信息" name="base">
<el-form ref="supplierRef" :model="form" :rules="rules" label-width="120px" class="supplier-form">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="供应商编码" prop="supplierCode">
<el-input v-model="form.supplierCode" placeholder="请输入供应商编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商名称" prop="supplierName">
<el-input v-model="form.supplierName" placeholder="请输入供应商名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="对外代码" prop="supplierCodeDw">
<el-input v-model="form.supplierCodeDw" placeholder="请输入对外代码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="统一社会信用代码" prop="creditCode">
<el-input v-model="form.creditCode" placeholder="在「公司主体」页签点绑定供应商后自动同步">
<template #append>
<el-tooltip content="由公司主体绑定自动同步,也可手工录入" placement="top">
<el-icon><InfoFilled /></el-icon>
</el-tooltip>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商类型" prop="supplierType">
<el-select v-model="form.supplierType" placeholder="请选择供应商类型" clearable style="width: 100%;">
<el-option v-for="opt in supplierTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开票类型" prop="invoiceType">
<el-select v-model="form.invoiceType" placeholder="请选择开票类型" clearable style="width: 100%;">
<el-option v-for="opt in invoiceTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="卡车行类型" prop="kacheType">
<el-select v-model="form.kacheType" placeholder="请选择卡车行类型" clearable style="width: 100%;">
<el-option v-for="opt in kacheTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="启用状态" prop="isEnable">
<el-select v-model="form.isEnable" placeholder="请选择启用状态" clearable style="width: 100%;">
<el-option label="正常" value="0" />
<el-option label="停用" value="1" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="采购员" prop="purchaserUserId">
<user-select
v-model="form.purchaserUserId"
placeholder="请选择采购员"
@change="(uid, user) => handleUserChange(uid, user, 'purchaserUser')"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="应付额度" prop="ed">
<el-input v-model="form.ed" placeholder="请输入应付额度" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="应付账期" prop="zq">
<el-input v-model="form.zq" placeholder="请输入应付账期(天)" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结算员" prop="settlementUserId">
<user-select
v-model="form.settlementUserId"
placeholder="请选择结算员"
@change="(uid, user) => handleUserChange(uid, user, 'settlementUser')"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="跟单员" prop="serviceUserId">
<user-select
v-model="form.serviceUserId"
placeholder="请选择跟单员"
@change="(uid, user) => handleUserChange(uid, user, 'serviceUser')"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结算方式" prop="settlementType">
<el-select v-model="form.settlementType" placeholder="请选择结算方式" clearable style="width: 100%;">
<el-option
v-for="dict in settlement_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="临时额度" prop="tempEd">
<el-input v-model="form.tempEd" placeholder="请输入临时额度" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="应付余额" prop="accountBalance">
<el-input v-model="form.accountBalance" placeholder="请输入应付余额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="外币应付余额" prop="foreignCurrencyBalance">
<el-input v-model="form.foreignCurrencyBalance" placeholder="请输入外币应付余额" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="信用额度" prop="creditEd">
<el-input v-model="form.creditEd" placeholder="请输入信用额度" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="重量阈值" prop="weightThreshold">
<el-input v-model="form.weightThreshold" placeholder="请输入重量阈值(kg)" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="抛比" prop="throwRatio">
<el-input v-model="form.throwRatio" placeholder="请输入抛比(%)" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合作开始日期" prop="cooperationStartDate">
<el-date-picker v-model="form.cooperationStartDate" type="date" value-format="YYYY-MM-DD" placeholder="选择合作开始日期" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合作状态" prop="cooperationStatus">
<el-select v-model="form.cooperationStatus" placeholder="请选择合作状态" clearable style="width: 100%;">
<el-option v-for="opt in cooperationStatusOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="绑定渠道ID" prop="channelIds">
<el-input v-model="form.channelIds" type="textarea" :rows="2" placeholder="多个渠道ID用英文逗号分隔" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注说明" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入内容" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-tab-pane>
<!-- ============ 公司主体 ============ -->
<el-tab-pane label="公司主体" name="company">
<div class="pane-toolbar">
<el-button type="primary" plain icon="Plus" size="small" @click="handleAddCompany">新增公司主体</el-button>
<span class="pane-tip">点击「绑定供应商」后,主表的统一社会信用代码会自动同步为该公司的信用代码</span>
</div>
<el-table :data="form.companyList" border size="small">
<el-table-column label="序号" type="index" width="55" align="center" />
<el-table-column label="公司全称" prop="companyNameFull" show-overflow-tooltip />
<el-table-column label="统一社会信用代码" prop="creditCode" width="190" show-overflow-tooltip />
<el-table-column label="法定代表人" prop="legalPerson" width="110" show-overflow-tooltip />
<el-table-column label="当前绑定" width="90" align="center">
<template #default="{ row }">
<el-tag v-if="row.creditCode && form.creditCode === row.creditCode" type="success" size="small">已绑定</el-tag>
<span v-else style="color: #999;">-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="230" align="center">
<template #default="{ row, $index }">
<el-button link type="primary" size="small" @click="handleBindCompany(row)">绑定供应商</el-button>
<el-button link type="primary" size="small" @click="handleEditCompany(row, $index)">编辑</el-button>
<el-button link type="danger" size="small" @click="handleDeleteCompany(row, $index)">删除</el-button>
</template>
</el-table-column>
<template #empty>
<el-empty description="暂无公司主体,新增后将随供应商信息一起保存" :image-size="80" />
</template>
</el-table>
</el-tab-pane>
<!-- ============ 联系人 ============ -->
<el-tab-pane label="联系人" name="contact">
<div class="pane-toolbar">
<el-button type="primary" plain icon="Plus" size="small" @click="handleAddContact">新增联系人</el-button>
</div>
<el-table :data="form.contactList" border size="small">
<el-table-column label="序号" type="index" width="55" align="center" />
<el-table-column label="联系人" prop="contactName" width="120" show-overflow-tooltip />
<el-table-column label="职位" prop="position" width="130" show-overflow-tooltip />
<el-table-column label="所属部门" prop="department" width="130" show-overflow-tooltip />
<el-table-column label="手机号" prop="phone" width="140" show-overflow-tooltip />
<el-table-column label="邮箱" prop="email" min-width="180" show-overflow-tooltip />
<el-table-column label="默认" width="80" align="center">
<template #default="{ row }">
<el-tag v-if="row.isDefault === '1'" type="success" size="small">默认</el-tag>
<span v-else style="color: #999;">-</span>
</template>
</el-table-column>
<el-table-column label="操作" width="150" align="center">
<template #default="{ row, $index }">
<el-button link type="primary" size="small" @click="handleEditContact(row, $index)">编辑</el-button>
<el-button link type="danger" size="small" @click="handleDeleteContact(row, $index)">删除</el-button>
</template>
</el-table-column>
<template #empty>
<el-empty description="暂无联系人,新增后将随供应商信息一起保存" :image-size="80" />
</template>
</el-table>
</el-tab-pane>
<!-- ============ 附件资料 ============ -->
<el-tab-pane label="附件资料" name="attachment">
<div class="pane-toolbar">
<el-upload
:show-file-list="false"
:action="uploadFileUrl"
:headers="uploadHeaders"
:before-upload="handleBeforeAttachmentUpload"
:on-success="handleAttachmentUploadSuccess"
:on-error="handleAttachmentUploadError"
multiple
>
<el-button type="primary" icon="Upload">上传附件</el-button>
</el-upload>
<span class="pane-tip">支持 PDF、图片、Word、Excel、压缩包,单个文件不超过 50MB;附件在点「保存」后随供应商入库</span>
</div>
<el-table :data="form.attachmentList" border size="small">
<el-table-column label="序号" type="index" width="55" align="center" />
<el-table-column label="文件名称" prop="fileName" align="center" show-overflow-tooltip min-width="180">
<template #default="{ row }">
<el-button link type="primary" @click="handleDownload(row)">{{ row.fileName }}</el-button>
</template>
</el-table-column>
<el-table-column label="大小" width="100" align="center">
<template #default="{ row }">{{ formatFileSize(row.fileSize) }}</template>
</el-table-column>
<el-table-column label="类型" prop="fileExtension" width="80" align="center" />
<el-table-column label="附件分类" width="160" align="center">
<template #default="{ row }">
<el-select v-model="row.attachmentType" placeholder="请选择">
<el-option v-for="opt in attachmentTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="排序" width="90" align="center">
<template #default="{ row }">
<el-input v-model="row.sortOrder" type="number" />
</template>
</el-table-column>
<el-table-column label="备注" min-width="160" align="center">
<template #default="{ row }">
<el-input v-model="row.remark" placeholder="请输入备注" />
</template>
</el-table-column>
<el-table-column label="操作" width="130" align="center">
<template #default="{ row, $index }">
<el-button link type="primary" icon="Download" @click="handleDownload(row)">下载</el-button>
<el-button link type="danger" icon="Delete" @click="handleDeleteAttachment($index)">删除</el-button>
</template>
</el-table-column>
<template #empty>
<el-empty description="暂无附件" :image-size="80" />
</template>
</el-table>
</el-tab-pane>
</el-tabs>
</el-card>
<!-- ====== 公司主体编辑对话框 ====== -->
<el-dialog :title="companyDialogTitle" v-model="companyDialogVisible" width="900px" append-to-body>
<el-form ref="companyRef" :model="companyForm" label-width="130px">
<el-row>
<el-col :span="12">
<el-form-item label="公司全称" prop="companyNameFull">
<el-input v-model="companyForm.companyNameFull" placeholder="请输入公司全称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="英文名称" prop="englishName">
<el-input v-model="companyForm.englishName" placeholder="请输入英文名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="统一社会信用代码" prop="creditCode">
<el-input v-model="companyForm.creditCode" placeholder="18位统一社会信用代码" maxlength="18" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="法定代表人" prop="legalPerson">
<el-input v-model="companyForm.legalPerson" placeholder="请输入法定代表人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="法定代表人电话" prop="legalPersonPhone">
<el-input v-model="companyForm.legalPersonPhone" placeholder="请输入法定代表人电话" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="法定代表人身份证" prop="legalPersonIdCard">
<el-input v-model="companyForm.legalPersonIdCard" placeholder="请输入法定代表人身份证号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="注册资本" prop="registeredCapital">
<el-input-number v-model="companyForm.registeredCapital" :min="0" :precision="2" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="币种" prop="capitalCurrency">
<el-input v-model="companyForm.capitalCurrency" placeholder="如 人民币/美元" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实收资本" prop="paidInCapital">
<el-input-number v-model="companyForm.paidInCapital" :min="0" :precision="2" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="成立日期" prop="establishDate">
<el-date-picker v-model="companyForm.establishDate" type="date" value-format="YYYY-MM-DD" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="营业期限起" prop="businessTermStart">
<el-date-picker v-model="companyForm.businessTermStart" type="date" value-format="YYYY-MM-DD" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="营业期限止" prop="businessTermEnd">
<el-date-picker v-model="companyForm.businessTermEnd" type="date" value-format="YYYY-MM-DD" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="是否长期有效" prop="businessTermPermanent">
<el-radio-group v-model="companyForm.businessTermPermanent">
<el-radio label="0">否</el-radio>
<el-radio label="1">是</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="登记机关" prop="registrationAuthority">
<el-input v-model="companyForm.registrationAuthority" placeholder="请输入登记机关" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="注册号" prop="registrationNumber">
<el-input v-model="companyForm.registrationNumber" placeholder="旧版工商注册号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="经营状态" prop="operatingStatus">
<el-input v-model="companyForm.operatingStatus" placeholder="如 存续/在业/吊销/注销" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="员工人数" prop="employeeCount">
<el-input-number v-model="companyForm.employeeCount" :min="0" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="经营范围" prop="businessScope">
<el-input v-model="companyForm.businessScope" type="textarea" :rows="3" placeholder="请输入经营范围" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="主要股东" prop="shareholders">
<el-input v-model="companyForm.shareholders" type="textarea" :rows="2" placeholder="股东信息(文本或JSON)" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="公司电话" prop="companyPhone">
<el-input v-model="companyForm.companyPhone" placeholder="请输入公司电话" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="公司传真" prop="companyFax">
<el-input v-model="companyForm.companyFax" placeholder="请输入公司传真" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="公司网址" prop="companyWebsite">
<el-input v-model="companyForm.companyWebsite" placeholder="请输入公司网址" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="公司邮箱" prop="companyEmail">
<el-input v-model="companyForm.companyEmail" placeholder="请输入公司邮箱" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="省份" prop="registeredProvince" label-width="60px">
<el-input v-model="companyForm.registeredProvince" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="城市" prop="registeredCity" label-width="60px">
<el-input v-model="companyForm.registeredCity" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="区县" prop="registeredDistrict" label-width="60px">
<el-input v-model="companyForm.registeredDistrict" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="注册详细地址" prop="registeredAddressDetail">
<el-input v-model="companyForm.registeredAddressDetail" placeholder="请输入注册详细地址" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="营业执照" prop="businessLicenseUrl">
<image-upload v-model="companyForm.businessLicenseUrl" :limit="1" :size="5" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="其他附件" prop="attachmentIds">
<file-upload v-model="companyForm.attachmentIds" :limit="10" :size="50" accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx,.zip,.rar" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="companyForm.remark" type="textarea" :rows="2" placeholder="备注说明" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitCompanyForm">确 定</el-button>
<el-button @click="companyDialogVisible = false">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- ====== 联系人编辑对话框 ====== -->
<el-dialog :title="contactDialogTitle" v-model="contactDialogVisible" width="800px" append-to-body>
<el-form ref="contactRef" :model="contactForm" :rules="contactRules" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="联系人姓名" prop="contactName">
<el-input v-model="contactForm.contactName" placeholder="请输入联系人姓名" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="职位" prop="position">
<el-input v-model="contactForm.position" placeholder="如 销售经理/财务总监" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手机号" prop="phone">
<el-input v-model="contactForm.phone" placeholder="请输入手机号" maxlength="20" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属部门" prop="department">
<el-input v-model="contactForm.department" placeholder="如 销售部/财务部" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="座机" prop="landline">
<el-input v-model="contactForm.landline" placeholder="含区号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电子邮箱" prop="email">
<el-input v-model="contactForm.email" placeholder="请输入电子邮箱" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="微信号" prop="wechat">
<el-input v-model="contactForm.wechat" placeholder="请输入微信号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="QQ号" prop="qq">
<el-input v-model="contactForm.qq" placeholder="请输入QQ号" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="国家/地区" prop="country" label-width="90px">
<el-input v-model="contactForm.country" placeholder="中国" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="省份" prop="province" label-width="60px">
<el-input v-model="contactForm.province" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="城市" prop="city" label-width="60px">
<el-input v-model="contactForm.city" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="区/县" prop="district" label-width="60px">
<el-input v-model="contactForm.district" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮政编码" prop="postalCode">
<el-input v-model="contactForm.postalCode" placeholder="请输入邮政编码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="详细地址" prop="contactAddress">
<el-input v-model="contactForm.contactAddress" placeholder="街道、门牌号" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系人类型" prop="contactType">
<el-select v-model="contactForm.contactType" placeholder="请选择" clearable>
<el-option label="业务联系人" value="0" />
<el-option label="财务联系人" value="1" />
<el-option label="紧急联系人" value="2" />
<el-option label="其他" value="3" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否默认" prop="isDefault">
<el-radio-group v-model="contactForm.isDefault">
<el-radio label="0">否</el-radio>
<el-radio label="1">是</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="排序" prop="sortOrder">
<el-input-number v-model="contactForm.sortOrder" :min="0" controls-position="right" style="width: 100%;" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="contactForm.remark" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitContactForm">确 定</el-button>
<el-button @click="contactDialogVisible = false">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="SupplierEdit">
import {
getSupplier, addSupplier, updateSupplier,
delSupplierCompany, delSupplierContact
} from '@/api/customersuppliermanagement/supplierinfo/supplier.js'
import { getToken } from '@/utils/auth'
import axios from 'axios'
import { saveAs } from 'file-saver'
const { proxy } = getCurrentInstance()
const route = useRoute()
const router = useRouter()
const { settlement_type } = useDict('settlement_type')
const pageLoading = ref(false)
const saving = ref(false)
const activeTab = ref('base')
const supplierId = computed(() => route.query.supplierId ? Number(route.query.supplierId) : null)
const isAdd = computed(() => !supplierId.value)
const rules = {
supplierCode: [{ required: true, message: '供应商编码不能为空', trigger: 'blur' }],
supplierName: [{ required: true, message: '供应商名称不能为空', trigger: 'blur' }]
}
const supplierTypeOptions = ref([
{ value: '1', label: '卡车行' },
{ value: '2', label: '航司代理' },
{ value: '3', label: '报关行' },
{ value: '4', label: '清关行' },
{ value: '5', label: '尾派服务商' },
{ value: '6', label: '报关代理' }
])
const invoiceTypeOptions = ref([
{ value: '1', label: '增值税普通发票' },
{ value: '2', label: '增值税专用发票' },
{ value: '3', label: '增值税电子普通发票' },
{ value: '4', label: '其他普通发票' }
])
const kacheTypeOptions = ref([
{ value: '0', label: '国内' },
{ value: '1', label: '国外' }
])
const cooperationStatusOptions = ref([
{ value: '0', label: '正常' },
{ value: '1', label: '暂停' },
{ value: '2', label: '终止' }
])
/** 空表单 */
function buildEmptyForm() {
return {
supplierId: null,
supplierCode: null,
supplierName: null,
supplierCodeDw: null,
creditCode: null,
supplierType: null,
invoiceType: null,
kacheType: null,
isEnable: null,
purchaserUserId: null,
purchaserUser: null,
ed: null,
zq: null,
settlementUserId: null,
settlementUser: null,
serviceUserId: null,
serviceUser: null,
settlementType: null,
tempEd: null,
accountBalance: null,
foreignCurrencyBalance: null,
weightThreshold: null,
throwRatio: null,
creditEd: null,
cooperationStartDate: null,
cooperationStatus: null,
channelIds: null,
attachmentList: [],
companyList: [],
contactList: [],
remark: null,
delFlag: null
}
}
const form = ref(buildEmptyForm())
/* ---------------- 用户冗余姓名 ---------------- */
function handleUserChange(uid, user, nameField) {
form.value[nameField] = user ? (user.nickName || user.userName || null) : null
}
/* ---------------- 附件上传 ---------------- */
const baseUrl = import.meta.env.VITE_APP_BASE_API
const uploadFileUrl = ref(baseUrl + '/common/upload')
const uploadHeaders = ref({ Authorization: 'Bearer ' + getToken() })
const attachmentTypeOptions = ref([
{ value: '0', label: '附件资料' },
{ value: '1', label: '供应商Logo' },
{ value: '2', label: '合同文件' },
{ value: '3', label: '其他' }
])
const ATTACHMENT_SIZE_LIMIT = 50
const ATTACHMENT_EXTENSIONS = ['pdf', 'jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx', 'zip', 'rar']
function formatFileSize(bytes) {
if (!bytes) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
function handleBeforeAttachmentUpload(file) {
const ext = (file.name.split('.').pop() || '').toLowerCase()
if (ATTACHMENT_EXTENSIONS.indexOf(ext) < 0) {
proxy.$modal.msgError(`不支持的文件格式:${ext}`)
return false
}
if (file.name.includes(',')) {
proxy.$modal.msgError('文件名不正确,不能包含英文逗号!')
return false
}
if (file.size / 1024 / 1024 >= ATTACHMENT_SIZE_LIMIT) {
proxy.$modal.msgError(`上传文件大小不能超过 ${ATTACHMENT_SIZE_LIMIT} MB!`)
return false
}
proxy.$modal.loading('正在上传文件,请稍候...')
return true
}
function handleAttachmentUploadSuccess(res, file) {
proxy.$modal.closeLoading()
if (res.code === 200) {
form.value.attachmentList.push({
attachmentId: null,
supplierId: form.value.supplierId || null,
fileName: file.name,
filePath: res.fileName,
fileSize: file.size,
fileType: file.type || '',
fileExtension: (file.name.split('.').pop() || '').toLowerCase(),
attachmentType: '0',
isLogo: '0',
sortOrder: form.value.attachmentList.length,
remark: '',
delFlag: '0'
})
} else {
proxy.$modal.msgError(res.msg || '上传文件失败')
}
}
function handleAttachmentUploadError() {
proxy.$modal.closeLoading()
proxy.$modal.msgError('上传文件失败')
}
function handleDeleteAttachment(index) {
form.value.attachmentList.splice(index, 1)
}
/** 附件下载(携带鉴权头,并以原始文件名保存) */
function handleDownload(row) {
if (!row.filePath) {
proxy.$modal.msgWarning('该附件文件路径缺失,无法下载')
return
}
proxy.$modal.loading('正在下载文件,请稍候...')
axios({
method: 'get',
url: import.meta.env.VITE_APP_BASE_API + '/common/download/resource?resource=' + encodeURIComponent(row.filePath),
responseType: 'blob',
headers: { Authorization: 'Bearer ' + getToken() }
}).then(res => {
const blob = new Blob([res.data])
saveAs(blob, row.fileName)
}).catch(() => {
proxy.$modal.msgError('下载失败')
}).finally(() => {
proxy.$modal.closeLoading()
})
}
/* ============ 公司主体子表 ============ */
const companyDialogVisible = ref(false)
const companyDialogTitle = ref('')
const companyForm = ref({})
const companyEditingIndex = ref(-1)
function resetCompanyForm() {
companyForm.value = {
companyId: null,
supplierId: null,
companyNameFull: '',
englishName: '',
creditCode: '',
legalPerson: '',
legalPersonPhone: '',
legalPersonIdCard: '',
registeredCapital: 0,
capitalCurrency: '人民币',
paidInCapital: 0,
establishDate: null,
businessTermStart: null,
businessTermEnd: null,
businessTermPermanent: '0',
registrationAuthority: '',
registrationNumber: '',
operatingStatus: '',
businessScope: '',
shareholders: '',
employeeCount: 0,
companyPhone: '',
companyFax: '',
companyWebsite: '',
companyEmail: '',
registeredProvince: '',
registeredCity: '',
registeredDistrict: '',
registeredAddressDetail: '',
businessLicenseUrl: '',
attachmentIds: '',
remark: ''
}
proxy.resetForm('companyRef')
}
/** 新增公司主体:新增供应商态下仅存本地数组,保存主表时由后端补 supplierId 一并入库 */
function handleAddCompany() {
resetCompanyForm()
companyEditingIndex.value = -1
companyDialogTitle.value = '新增公司主体'
companyDialogVisible.value = true
}
function handleEditCompany(row, index) {
resetCompanyForm()
companyForm.value = { ...row }
companyEditingIndex.value = index
companyDialogTitle.value = '修改公司主体'
companyDialogVisible.value = true
}
/** 删除公司主体:本地新增行直接移除;已入库行先调删除接口 */
function handleDeleteCompany(row, index) {
proxy.$modal.confirm('是否确认删除该条公司主体记录?').then(() => {
const doRemove = () => {
const removed = form.value.companyList.splice(index, 1)[0]
if (removed && form.value.creditCode && removed.creditCode === form.value.creditCode) {
form.value.creditCode = ''
}
proxy.$modal.msgSuccess('删除成功')
}
if (row.companyId) {
delSupplierCompany(row.companyId).then(doRemove)
} else {
doRemove()
}
}).catch(() => {})
}
function handleBindCompany(row) {
if (!row.creditCode) {
proxy.$modal.msgWarning('该公司主体未填写统一社会信用代码,无法绑定')
return
}
form.value.creditCode = row.creditCode
if (row.companyNameFull && !form.value.supplierName) {
form.value.supplierName = row.companyNameFull
}
proxy.$modal.msgSuccess('绑定成功,主表统一社会信用代码已同步')
}
function submitCompanyForm() {
if (!companyForm.value.companyNameFull) {
proxy.$modal.msgWarning('公司全称不能为空')
return
}
if (!Array.isArray(form.value.companyList)) {
form.value.companyList = []
}
if (companyEditingIndex.value >= 0) {
form.value.companyList.splice(companyEditingIndex.value, 1, { ...companyForm.value })
if (form.value.creditCode && form.value.companyList[companyEditingIndex.value].creditCode !== form.value.creditCode) {
form.value.creditCode = form.value.companyList[companyEditingIndex.value].creditCode || form.value.creditCode
}
} else {
form.value.companyList.push({ ...companyForm.value })
}
companyDialogVisible.value = false
proxy.$modal.msgSuccess(companyEditingIndex.value >= 0 ? '修改成功' : '新增成功,保存供应商后生效')
}
/* ============ 联系人子表 ============ */
const contactDialogVisible = ref(false)
const contactDialogTitle = ref('')
const contactForm = ref({})
const contactEditingIndex = ref(-1)
const contactRules = {
contactName: [{ required: true, message: '联系人姓名不能为空', trigger: 'blur' }],
phone: [{ required: true, message: '手机号不能为空', trigger: 'blur' }]
}
function resetContactForm() {
contactForm.value = {
contactId: null,
supplierId: form.value.supplierId || null,
contactName: '',
position: '',
department: '',
phone: '',
landline: '',
email: '',
wechat: '',
qq: '',
country: '中国',
province: '',
city: '',
district: '',
contactAddress: '',
postalCode: '',
isDefault: '0',
contactType: '0',
sortOrder: 0,
remark: ''
}
proxy.resetForm('contactRef')
}
function handleAddContact() {
resetContactForm()
contactEditingIndex.value = -1
contactDialogTitle.value = '新增联系人'
contactDialogVisible.value = true
}
function handleEditContact(row, index) {
resetContactForm()
contactForm.value = { ...row }
contactEditingIndex.value = index
contactDialogTitle.value = '修改联系人'
contactDialogVisible.value = true
}
/** 删除联系人:本地新增行直接移除;已入库行先调删除接口 */
function handleDeleteContact(row, index) {
proxy.$modal.confirm('是否确认删除该条联系人记录?').then(() => {
if (row.contactId) {
delSupplierContact(row.contactId).then(() => {
form.value.contactList.splice(index, 1)
proxy.$modal.msgSuccess('删除成功')
})
} else {
form.value.contactList.splice(index, 1)
proxy.$modal.msgSuccess('删除成功')
}
}).catch(() => {})
}
function submitContactForm() {
if (!contactForm.value.contactName) {
proxy.$modal.msgWarning('联系人姓名不能为空')
return
}
if (!Array.isArray(form.value.contactList)) {
form.value.contactList = []
}
if (contactEditingIndex.value >= 0) {
form.value.contactList.splice(contactEditingIndex.value, 1, { ...contactForm.value })
} else {
form.value.contactList.push({ ...contactForm.value })
}
contactDialogVisible.value = false
proxy.$modal.msgSuccess(contactEditingIndex.value >= 0 ? '修改成功' : '新增成功,保存供应商后生效')
}
/* ============ 加载 / 保存 ============ */
/** 重新拉取详情(新增保存后或修改保存后调用,确保子表主键、附件重建结果与库一致) */
function loadDetail(id) {
return getSupplier(id).then(response => {
if (!response.data) {
proxy.$modal.msgError('该供应商不存在或已被删除')
return
}
form.value = response.data
form.value.attachmentList = form.value.attachmentList || []
form.value.companyList = form.value.companyList || []
form.value.contactList = form.value.contactList || []
})
}
/** 保存:新增成功后留在本页(URL 替换为编辑态),可继续维护子表 */
function submitForm() {
proxy.$refs['supplierRef'].validate(valid => {
if (!valid) {
activeTab.value = 'base'
return
}
const nullIfEmpty = v => (v === '' || v === undefined ? null : v)
const payload = {
...form.value,
purchaserUserId: nullIfEmpty(form.value.purchaserUserId),
purchaserUser: nullIfEmpty(form.value.purchaserUser),
settlementUserId: nullIfEmpty(form.value.settlementUserId),
settlementUser: nullIfEmpty(form.value.settlementUser),
serviceUserId: nullIfEmpty(form.value.serviceUserId),
serviceUser: nullIfEmpty(form.value.serviceUser)
}
saving.value = true
const req = isAdd.value ? addSupplier(payload) : updateSupplier(payload)
req.then(res => {
if (isAdd.value) {
const newId = res.supplierId || res.data?.supplierId
proxy.$modal.msgSuccess('新增成功,已进入编辑页,可继续维护公司主体、联系人和附件')
// 替换为编辑态(query 变化触发 watch 自动拉取详情),避免返回/刷新再次新增
router.replace({ path: '/customersupplier/supplier-edit/index', query: { supplierId: newId } })
return
}
proxy.$modal.msgSuccess('保存成功')
return loadDetail(form.value.supplierId)
}).finally(() => {
saving.value = false
})
})
}
function goBack() {
router.push({ path: '/customersuppliermanagement/supplierinfo' })
}
/* ============ 初始化 ============ */
/** 按当前路由初始化页面:有supplierId拉详情,无则空表单(同路由组件复用时靠 watch 触发) */
function initByRoute() {
companyDialogVisible.value = false
contactDialogVisible.value = false
activeTab.value = 'base'
if (supplierId.value) {
pageLoading.value = true
loadDetail(supplierId.value).finally(() => { pageLoading.value = false })
} else {
form.value = buildEmptyForm()
}
}
watch(() => route.query.supplierId, (newVal, oldVal) => {
if (String(newVal || '') === String(oldVal || '')) return
initByRoute()
})
onMounted(() => {
initByRoute()
})
</script>
<style lang="scss" scoped>
.head-card {
margin-bottom: 12px;
}
.head-bar {
display: flex;
align-items: center;
gap: 14px;
}
.head-title {
display: flex;
align-items: center;
gap: 8px;
}
.supplier-name {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.head-code {
color: #909399;
font-size: 13px;
}
.head-right {
margin-left: auto;
}
.pane-toolbar {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.pane-tip {
color: #909399;
font-size: 12px;
}
</style>