|
|
@@ -0,0 +1,3581 @@
|
|
|
+<template>
|
|
|
+ <div class="app-container">
|
|
|
+ <!-- 页面头部 -->
|
|
|
+ <div class="detail-header">
|
|
|
+ <el-icon class="back-icon" @click="goBack"><ArrowLeft /></el-icon>
|
|
|
+ <span class="header-title">查看供应商</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 标签页 -->
|
|
|
+ <el-tabs v-model="activeTab" class="detail-tabs">
|
|
|
+ <!-- 基本信息 -->
|
|
|
+ <el-tab-pane label="基本信息" name="basic">
|
|
|
+ <div class="tab-content">
|
|
|
+ <!-- 企业基本信息 -->
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-title-left">
|
|
|
+ <span class="section-title-text">企业基本信息</span>
|
|
|
+ <span class="section-title-divider">/</span>
|
|
|
+ <span class="supplier-no">供应商编码:{{ detailData.supplierNo }}</span>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" icon="Document" @click="handleSave">保存</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-form :model="detailData" label-width="100px" class="detail-form">
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="所属公司:" required>
|
|
|
+ <el-select v-model="detailData.ownedCompany" placeholder="请选择" clearable filterable style="width: 100%;" disabled>
|
|
|
+ <el-option
|
|
|
+ v-for="company in companyOptions"
|
|
|
+ :key="company.id"
|
|
|
+ :label="company.companyName"
|
|
|
+ :value="company.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="企业名称:" required>
|
|
|
+ <el-input v-model="detailData.enterpriseName" placeholder="请输入企业名称" disabled>
|
|
|
+ <template #append v-if="isAddMode && !isBasicInfoSaved">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="handleGetBusinessInfo"
|
|
|
+ :loading="businessInfoLoading"
|
|
|
+ :icon="businessInfoLoading ? '' : 'Search'"
|
|
|
+ >
|
|
|
+ {{ businessInfoLoading ? '获取中...' : '获取工商信息' }}
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="工商名称:">
|
|
|
+ <el-input v-model="detailData.businessName" placeholder="请输入工商名称" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="企业简称:" required>
|
|
|
+ <el-input v-model="detailData.shortName" placeholder="请输入企业简称" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="供应商等级:" required>
|
|
|
+ <el-select v-model="detailData.cooperateLevel" placeholder="请选择" clearable filterable style="width: 100%;" disabled>
|
|
|
+ <el-option
|
|
|
+ v-for="level in supplierLevelOptions"
|
|
|
+ :key="level.id"
|
|
|
+ :label="level.supplierLevelName"
|
|
|
+ :value="String(level.id)"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="企业规模:" required>
|
|
|
+ <el-select v-model="detailData.membershipSize" placeholder="请选择" clearable filterable style="width: 100%;" disabled>
|
|
|
+ <el-option
|
|
|
+ v-for="scale in enterpriseScaleOptions"
|
|
|
+ :key="scale.id"
|
|
|
+ :label="scale.enterpriseScaleName"
|
|
|
+ :value="scale.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="行业类别:" required>
|
|
|
+ <el-select v-model="detailData.industrCategory" placeholder="请选择" clearable filterable style="width: 100%;" disabled>
|
|
|
+ <el-option
|
|
|
+ v-for="industry in industryCategoryOptions"
|
|
|
+ :key="industry.id"
|
|
|
+ :label="industry.industryCategoryName"
|
|
|
+ :value="industry.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="供应商类型:" required>
|
|
|
+ <el-select v-model="detailData.supplierType" placeholder="请选择" clearable filterable style="width: 100%;" disabled>
|
|
|
+ <el-option
|
|
|
+ v-for="type in supplierTypeOptions"
|
|
|
+ :key="type.id"
|
|
|
+ :label="type.supplierTypeName"
|
|
|
+ :value="type.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="固定电话:">
|
|
|
+ <el-input v-model="detailData.fixedPhone" placeholder="请输入固定电话" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="传真:">
|
|
|
+ <el-input v-model="detailData.fax" placeholder="请输入传真" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="企业邮箱:">
|
|
|
+ <el-input v-model="detailData.mailbox" placeholder="请输入企业邮箱" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="开始时间:">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="detailData.validityFromDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%;"
|
|
|
+ disabled
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="结束时间:">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="detailData.validityToDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%;"
|
|
|
+ disabled
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="邮政编码:">
|
|
|
+ <el-input v-model="detailData.postCode" placeholder="请输入邮政编码" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="网址:">
|
|
|
+ <el-input v-model="detailData.url" placeholder="请输入网址" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="详细地址:" required>
|
|
|
+ <el-cascader
|
|
|
+ v-model="selectedOfficeRegion"
|
|
|
+ :options="regionOptions"
|
|
|
+ :props="regionCascaderProps"
|
|
|
+ placeholder="请选择省市区"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleOfficeRegionChange"
|
|
|
+ disabled
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label=" " label-width="0">
|
|
|
+ <el-input v-model="detailData.officeAddress" placeholder="请输入详细地址" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 工商信息 -->
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title">工商信息</div>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">企业工商名称:</span>
|
|
|
+ <span class="value">{{ businessInfo.businessName || detailData.businessName || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">登记机关:</span>
|
|
|
+ <span class="value">{{ businessInfo.registrationAuthority || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">成立日期:</span>
|
|
|
+ <span class="value">{{ formatDate(businessInfo.establishmentDate) || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">登记状态:</span>
|
|
|
+ <span class="value">{{ businessInfo.registrationStatus || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">实缴资本:</span>
|
|
|
+ <span class="value">{{ businessInfo.paidInCapital || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">社会信用代码:</span>
|
|
|
+ <span class="value">{{ businessInfo.socialCreditCode || detailData.socialCreditCode || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">法人姓名:</span>
|
|
|
+ <span class="value">{{ businessInfo.legalPersonName || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">注册资本:</span>
|
|
|
+ <span class="value">{{ businessInfo.registeredCapital || '' }}</span>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="24">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">工商地址:</span>
|
|
|
+ <el-input v-model="businessInfo.businessAddress" placeholder="工商地址" style="width: 70%;" />
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 付款信息 -->
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title">
|
|
|
+ 付款信息
|
|
|
+ </div>
|
|
|
+ <el-table :data="paymentInfoList" border style="width: 100%">
|
|
|
+ <el-table-column prop="num" label="是否主账号" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.num === 1 ? '是' : '否' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="bankName" label="开户银行" align="center" />
|
|
|
+ <el-table-column prop="bankNo" label="银行账户" align="center" />
|
|
|
+
|
|
|
+
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <div v-if="paymentInfoList.length === 0" style="text-align: center; padding: 40px; color: #999;">
|
|
|
+ 暂无付款信息
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 采购信息 -->
|
|
|
+ <el-tab-pane label="采销信息" name="purchase" :disabled="isAddMode && !isBasicInfoSaved">
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title">
|
|
|
+ 采购信息
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-row :gutter="40" class="form-row">
|
|
|
+ <el-col :span="12">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">产品经理:</span>
|
|
|
+ <el-select
|
|
|
+ v-model="selectedProductManager"
|
|
|
+ placeholder="请选择产品经理"
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ style="width: 300px;"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in staffOptions"
|
|
|
+ :key="item.staffId"
|
|
|
+ :label="item.displayText"
|
|
|
+ :value="item.staffId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <div class="form-item">
|
|
|
+ <span class="label">采购员:</span>
|
|
|
+ <el-select
|
|
|
+ v-model="selectedBuyer"
|
|
|
+ placeholder="请选择采购员"
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ style="width: 300px;"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in staffOptions"
|
|
|
+ :key="item.staffId"
|
|
|
+ :label="item.displayText"
|
|
|
+ :value="item.staffId"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 联系人 -->
|
|
|
+ <el-tab-pane label="联系人" name="contact" :disabled="isAddMode && !isBasicInfoSaved">
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-title-left">
|
|
|
+ <span class="section-title-text">业务联系人</span>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" icon="Plus" @click="handleAddContact">新增联系人</el-button>
|
|
|
+ </div>
|
|
|
+ <!-- 联系人表格 -->
|
|
|
+ <el-table v-loading="contactLoading" :data="contactList" border style="width: 100%">
|
|
|
+ <el-table-column prop="supplierName" label="所属供应商" align="center" />
|
|
|
+ <el-table-column prop="userNo" label="用户ID" align="center" />
|
|
|
+ <el-table-column prop="abutment_no" label="A10标识号" align="center" />
|
|
|
+ <el-table-column prop="userName" label="员工姓名" align="center" />
|
|
|
+ <el-table-column prop="phone" label="手机号" align="center" />
|
|
|
+ <el-table-column prop="roleNo" label="角色" align="center" />
|
|
|
+ <el-table-column prop="departmentNo" label="部门" align="center" />
|
|
|
+ <el-table-column prop="position" label="职位" align="center" />
|
|
|
+ <el-table-column prop="isPrimaryContact" label="主要联系人" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.isPrimaryContact === '1' ? '是' : '否' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="isRegister" label="允许登录供应商端" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.isRegister === '1' ? '是' : '否' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button link type="primary" @click="handleViewContact(scope.row)">查看</el-button>
|
|
|
+ <el-button link type="primary" @click="handleEditContact(scope.row)">编辑</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 供应信息 -->
|
|
|
+ <el-tab-pane label="供应信息" name="supply" :disabled="isAddMode && !isBasicInfoSaved">
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-title-left">
|
|
|
+ <span class="section-title-text">供货类目</span>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" icon="Document" @click="handleSaveCategories">保存</el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 产品分类复选框 -->
|
|
|
+ <el-checkbox-group v-model="selectedCategories" class="category-group">
|
|
|
+ <el-checkbox
|
|
|
+ v-for="category in productCategoryList"
|
|
|
+ :key="category.id"
|
|
|
+ :label="String(category.id)"
|
|
|
+ >
|
|
|
+ {{ category.categoryName }}
|
|
|
+ </el-checkbox>
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-title-left">
|
|
|
+ <span class="section-title-text">供货品牌</span>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <el-button type="primary" icon="Plus" @click="handleAddBrand">编辑</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="brand-display-wrapper">
|
|
|
+ <el-tag
|
|
|
+ v-for="brand in selectedBrands"
|
|
|
+ :key="brand.id"
|
|
|
+ closable
|
|
|
+ @close="handleRemoveBrand(brand)"
|
|
|
+ style="margin-right: 10px; margin-bottom: 10px;"
|
|
|
+ >
|
|
|
+ {{ brand.brandName }}
|
|
|
+ </el-tag>
|
|
|
+ <span v-if="selectedBrands.length === 0" style="color: #999;">暂无品牌信息</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-title-left">
|
|
|
+ <span class="section-title-text">供货区域</span>
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" icon="Edit" @click="handleEditSupplyArea">编辑</el-button>
|
|
|
+ </div>
|
|
|
+ <el-table :data="supplyAreaList" border style="width: 100%">
|
|
|
+ <el-table-column type="index" label="序号" align="center" width="80" />
|
|
|
+ <el-table-column prop="province" label="供货区域(省)" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.province || '' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="city" label="供货区域(市)" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.city || '' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title">授权详情信息列表</div>
|
|
|
+ <el-table :data="authorizationList" border style="width: 100%">
|
|
|
+ <el-table-column prop="supplierName" label="供应商名称" align="center" />
|
|
|
+ <el-table-column prop="brandName" label="品牌名称" align="center" />
|
|
|
+ <el-table-column label="一级类目" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.categorysMap?.oneLevelName || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="二级类目" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.categorysMap?.twoLevelName || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="三级类目" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.categorysMap?.threeLevelName || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="authorizationEndTime" label="禁止时间" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.authorizationEndTime ? formatDate(scope.row.authorizationEndTime) : '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="province" label="授权区域(省)" align="center" />
|
|
|
+ <el-table-column prop="city" label="授权区域(市)" align="center" />
|
|
|
+ <el-table-column prop="authorizedStatus" label="状态" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ getAuthorizedStatusText(scope.row.authorizedStatus) }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div style="margin-top: 20px; display: flex; justify-content: flex-end;">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="authorizationPagination.pageNum"
|
|
|
+ v-model:page-size="authorizationPagination.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :total="authorizationPagination.total"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleAuthorizationSizeChange"
|
|
|
+ @current-change="handleAuthorizationCurrentChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 地址管理 -->
|
|
|
+ <el-tab-pane label="地址管理" name="address" :disabled="isAddMode && !isBasicInfoSaved">
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="info-section">
|
|
|
+ <div class="section-title">地址信息列表</div>
|
|
|
+ <el-button icon="Plus" type="primary" @click="handleAddAddress">添加地址</el-button>
|
|
|
+ <el-table :data="addressList" border style="width: 100%">
|
|
|
+ <el-table-column prop="supplierNo" label="供应商编号" align="center" />
|
|
|
+ <el-table-column prop="addressNo" label="地址编号" align="center" />
|
|
|
+ <el-table-column prop="shipperName" label="姓名" align="center" />
|
|
|
+ <el-table-column prop="shipperPhone" label="手机号码" align="center" />
|
|
|
+ <el-table-column prop="shippingProvincial" label="省份" align="center" />
|
|
|
+ <el-table-column prop="shippingCity" label="市" align="center" />
|
|
|
+ <el-table-column prop="shippingCounty" label="区县" align="center" />
|
|
|
+ <el-table-column label="详细地址" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.shippingAddress || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="shippingPostCode" label="邮政编码" align="center" />
|
|
|
+ <el-table-column prop="isSelf" label="默认地址" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.isSelf === 1 || scope.row.isSelf === '1' ? '是' : '否' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" width="150">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button link type="primary" @click="handleEditAddress(scope.row)">编辑</el-button>
|
|
|
+ <el-button link type="danger" @click="handleDeleteAddress(scope.row)">删除</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <div v-if="addressList.length === 0" style="text-align: center; padding: 40px; color: #999;">
|
|
|
+ 暂无地址信息
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <!-- 合同管理 -->
|
|
|
+ <el-tab-pane label="合同管理" name="contract" :disabled="isAddMode && !isBasicInfoSaved">
|
|
|
+ <div class="tab-content">
|
|
|
+ <div class="info-section">
|
|
|
+ <!-- 搜索表单 -->
|
|
|
+ <el-form :model="contractSearchParams" :inline="true" style="margin-bottom: 20px;">
|
|
|
+ <el-form-item label="合同编号">
|
|
|
+ <el-input v-model="contractSearchParams.contractNo" placeholder="请输入合同编号" clearable style="width: 200px;" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="合同名称">
|
|
|
+ <el-input v-model="contractSearchParams.contractName" placeholder="请输入合同名称" clearable style="width: 200px;" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="合同类型">
|
|
|
+ <el-select v-model="contractSearchParams.contractType" placeholder="请选择" clearable filterable style="width: 150px;">
|
|
|
+ <el-option label="年度合作" value="0" />
|
|
|
+ <el-option label="项目采购" value="1" />
|
|
|
+ <el-option label="其他合作" value="2" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="Search" @click="handleContractSearch">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="handleContractReset">重置</el-button>
|
|
|
+
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <div class="section-title">合同信息列表</div>
|
|
|
+
|
|
|
+ <!-- 合同表格 -->
|
|
|
+ <el-table :data="contractList" border style="width: 100%">
|
|
|
+ <el-table-column prop="contractNo" label="合同编号" align="center" />
|
|
|
+ <el-table-column prop="contractName" label="合同名称" align="center" />
|
|
|
+ <el-table-column prop="contractType" label="合同类型" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ getContractTypeText(scope.row.contractType) }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="contractAmount" label="金额(万)" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.contractAmount || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="contractStartTime" label="起始时间" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.contractStartTime ? formatDate(scope.row.contractStartTime) : '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="contractEndTime" label="截止时间" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.contractEndTime ? formatDate(scope.row.contractEndTime) : '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="createTime" label="上传时间" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ scope.row.createTime ? formatDate(scope.row.createTime) : '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="contractAttachment" label="附件管理" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button v-if="scope.row.contractAttachment" link type="primary" @click="handleViewAttachment(scope.row)">查看附件</el-button>
|
|
|
+ <span v-else>-</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="contractStatus" label="状态" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ getContractStatusText(scope.row.contractStatus) }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" width="80">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button link type="primary" @click="handleViewContract(scope.row)">查看</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div style="margin-top: 20px; display: flex; justify-content: flex-end;">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="contractPagination.pageNum"
|
|
|
+ v-model:page-size="contractPagination.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100]"
|
|
|
+ :total="contractPagination.total"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleContractSizeChange"
|
|
|
+ @current-change="handleContractCurrentChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+
|
|
|
+ <!-- 营业执照选择器 -->
|
|
|
+ <FileSelector
|
|
|
+ v-model="businessLicenseDialogVisible"
|
|
|
+ :allowed-types="[1]"
|
|
|
+ :multiple="false"
|
|
|
+ title="选择营业执照"
|
|
|
+ @confirm="handleBusinessLicenseConfirm"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 法人身份证照片选择器 -->
|
|
|
+ <FileSelector
|
|
|
+ v-model="personImageDialogVisible"
|
|
|
+ :allowed-types="[1]"
|
|
|
+ :multiple="false"
|
|
|
+ title="选择法人身份证照片"
|
|
|
+ @confirm="handlePersonImageConfirm"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 付款信息对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="paymentDialogVisible"
|
|
|
+ :title="paymentDialogTitle"
|
|
|
+ width="1000px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-form
|
|
|
+ ref="paymentFormRef"
|
|
|
+ :model="paymentForm"
|
|
|
+ :rules="paymentFormRules"
|
|
|
+ label-width="140px"
|
|
|
+ :disabled="paymentDialogReadonly"
|
|
|
+ >
|
|
|
+ <el-form-item label="开票类型:" prop="invoiceTypeNo">
|
|
|
+ <el-select
|
|
|
+ v-model="paymentForm.invoiceTypeNo"
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleInvoiceTypeChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in invoiceTypeList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.invoiceTypeName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="发票抬头:" prop="businessName">
|
|
|
+ <el-input v-model="paymentForm.businessName" placeholder="企业工商名称" disabled/>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="纳税人识别号:" prop="circlesName">
|
|
|
+ <el-input v-model="paymentForm.circlesName" placeholder="请输入纳税人识别号" disabled/>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="开户行行号:" prop="bankNum">
|
|
|
+ <el-input v-model="paymentForm.bankNum" placeholder="请输入开户行行号" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="开户行名称:" prop="bankInfoNo">
|
|
|
+ <el-select
|
|
|
+ v-model="paymentForm.bankInfoNo"
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleBankChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in systemBankList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.bnName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="银行账户:" prop="bankNo">
|
|
|
+ <el-input v-model="paymentForm.bankNo" placeholder="请输入银行账户" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="固定电话:" prop="phone">
|
|
|
+ <el-input v-model="paymentForm.phone" placeholder="请输入固定电话" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="地址:" prop="businessAddress">
|
|
|
+ <el-input v-model="paymentForm.businessAddress" placeholder="工商地址" disabled />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <el-form-item label="是否主账号:" prop="num">
|
|
|
+ <el-radio-group v-model="paymentForm.num">
|
|
|
+ <el-radio :label="1">是</el-radio>
|
|
|
+ <el-radio :label="0">否</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="paymentDialogVisible = false">取消</el-button>
|
|
|
+ <el-button v-if="!paymentDialogReadonly" type="primary" @click="handlePaymentSubmit" :loading="paymentSubmitLoading">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 联系人对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="contactDialogVisible"
|
|
|
+ :title="contactDialogTitle"
|
|
|
+ width="900px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-form
|
|
|
+ ref="contactFormRef"
|
|
|
+ :model="contactForm"
|
|
|
+ :rules="contactFormRules"
|
|
|
+ label-width="140px"
|
|
|
+ :disabled="contactDialogReadonly"
|
|
|
+ >
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="员工姓名:" prop="userName">
|
|
|
+ <el-input v-model="contactForm.userName" placeholder="请输入员工姓名" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="手机号:" prop="phone">
|
|
|
+ <el-input v-model="contactForm.phone" placeholder="请输入手机号" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="部门:" prop="departmentNo">
|
|
|
+ <el-input v-model="contactForm.departmentNo" 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-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="角色:" prop="roleNo">
|
|
|
+ <el-input v-model="contactForm.roleNo" 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-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="主要联系人:" prop="isPrimaryContact">
|
|
|
+ <el-select v-model="contactForm.isPrimaryContact" placeholder="请选择" style="width: 100%;">
|
|
|
+ <el-option label="是" value="1" />
|
|
|
+ <el-option label="否" value="0" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="允许登录供应商端:" prop="isRegister">
|
|
|
+ <el-select v-model="contactForm.isRegister" placeholder="请选择" style="width: 100%;">
|
|
|
+ <el-option label="是" value="1" />
|
|
|
+ <el-option label="否" value="0" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="传真:" prop="fax">
|
|
|
+ <el-input v-model="contactForm.fax" placeholder="请输入传真" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="备注:" prop="remark">
|
|
|
+ <el-input
|
|
|
+ v-model="contactForm.remark"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ placeholder="请输入备注"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="contactDialogVisible = false">取消</el-button>
|
|
|
+ <el-button v-if="!contactDialogReadonly" type="primary" @click="handleContactSubmit" :loading="contactSubmitLoading">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 供货区域编辑对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="supplyAreaDialogVisible"
|
|
|
+ title="编辑供货区域"
|
|
|
+ width="700px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-cascader
|
|
|
+ v-model="selectedSupplyAreas"
|
|
|
+ :options="supplyAreaOptions"
|
|
|
+ :props="cascaderProps"
|
|
|
+ placeholder="请选择供货区域"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ collapse-tags
|
|
|
+ collapse-tags-tooltip
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="supplyAreaDialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleSupplyAreaSubmit" :loading="supplyAreaSubmitLoading">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 地址管理对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="addressDialogVisible"
|
|
|
+ :title="addressDialogTitle"
|
|
|
+ width="650px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-form
|
|
|
+ ref="addressFormRef"
|
|
|
+ :model="addressForm"
|
|
|
+ :rules="addressFormRules"
|
|
|
+ label-width="120px"
|
|
|
+ :disabled="addressDialogReadonly"
|
|
|
+ >
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="供应商编号:">
|
|
|
+ <el-input v-model="addressForm.supplierNo" disabled />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="收货人:" prop="shipperName" required>
|
|
|
+ <el-input v-model="addressForm.shipperName" placeholder="请输入收货人" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="手机号码:" prop="shipperPhone" required>
|
|
|
+ <el-input v-model="addressForm.shipperPhone" placeholder="请输入手机号码" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="邮政编码:" prop="shippingPostCode">
|
|
|
+ <el-input v-model="addressForm.shippingPostCode" placeholder="请输入邮政编码" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="地址:" prop="shippingProvincial" required>
|
|
|
+ <el-cascader
|
|
|
+ v-model="selectedAddressRegion"
|
|
|
+ :options="regionOptions"
|
|
|
+ :props="regionCascaderProps"
|
|
|
+ placeholder="请选择"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ style="width: 100%;"
|
|
|
+ @change="handleAddressRegionChange"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="详细地址:" prop="shippingAddress">
|
|
|
+ <el-input
|
|
|
+ v-model="addressForm.shippingAddress"
|
|
|
+ type="textarea"
|
|
|
+ :rows="3"
|
|
|
+ placeholder="请输入详细地址"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="默认地址:">
|
|
|
+ <el-switch v-model="addressForm.isSelf" :active-value="1" :inactive-value="0" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="addressDialogVisible = false">取消</el-button>
|
|
|
+ <el-button v-if="!addressDialogReadonly" type="primary" @click="handleAddressSubmit" :loading="addressSubmitLoading">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 合同管理对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="contractDialogVisible"
|
|
|
+ :title="contractDialogTitle"
|
|
|
+ width="900px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <el-form
|
|
|
+ ref="contractFormRef"
|
|
|
+ :model="contractForm"
|
|
|
+ :rules="contractFormRules"
|
|
|
+ label-width="140px"
|
|
|
+ :disabled="contractDialogReadonly"
|
|
|
+ >
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="合同名称:" prop="contractName">
|
|
|
+ <el-input v-model="contractForm.contractName" placeholder="请输入合同名称" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="合同类型:" prop="contractType">
|
|
|
+ <el-select v-model="contractForm.contractType" placeholder="请选择" style="width: 100%;">
|
|
|
+ <el-option
|
|
|
+ v-for="item in contractTypeDict"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="item.dictValue"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="提醒时间:" prop="demandReminderTime">
|
|
|
+ <el-input-number
|
|
|
+ v-model="contractForm.demandReminderTime"
|
|
|
+ :min="1"
|
|
|
+ :max="365"
|
|
|
+ style="width: 150px;"
|
|
|
+ />
|
|
|
+ <span style="margin-left: 10px;">天</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="开始时间:" prop="contractStartTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="contractForm.contractStartTime"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="截止时间:" prop="contractEndTime">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="contractForm.contractEndTime"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="开票类型:" prop="invoiceType">
|
|
|
+ <el-select v-model="contractForm.invoiceType" placeholder="请选择" style="width: 100%;">
|
|
|
+ <el-option
|
|
|
+ v-for="item in invoiceTypeList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.invoiceTypeName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="合同金额:" prop="contractAmount">
|
|
|
+ <el-input v-model="contractForm.contractAmount" placeholder="请输入">
|
|
|
+ <template #append>万元</template>
|
|
|
+ </el-input>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="税率:" prop="taxRate">
|
|
|
+ <el-select v-model="contractForm.taxRate" placeholder="请选择" style="width: 100%;">
|
|
|
+ <el-option
|
|
|
+ v-for="item in taxRateList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.taxrateName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="结算方式:" prop="settlementMethod">
|
|
|
+ <el-select v-model="contractForm.settlementMethod" placeholder="请选择" style="width: 100%;">
|
|
|
+ <el-option
|
|
|
+ v-for="item in settlementMethodList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="item.settlementName"
|
|
|
+ :value="item.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="合同附件:" prop="contractAttachment">
|
|
|
+ <FileUpload
|
|
|
+ v-model="contractForm.contractAttachment"
|
|
|
+ :limit="10"
|
|
|
+ :file-size="50"
|
|
|
+ :file-type="['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf']"
|
|
|
+ :disabled="contractDialogReadonly"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="24">
|
|
|
+ <el-form-item label="合同说明:" prop="contractDescription">
|
|
|
+ <el-input
|
|
|
+ v-model="contractForm.contractDescription"
|
|
|
+ type="textarea"
|
|
|
+ :rows="4"
|
|
|
+ placeholder="请输入合同说明"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="contractDialogVisible = false">取消</el-button>
|
|
|
+ <el-button v-if="!contractDialogReadonly" type="primary" @click="handleContractSubmit" :loading="contractSubmitLoading">确定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 品牌新增对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="brandDialogVisible"
|
|
|
+ title="添加品牌"
|
|
|
+ width="600px"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ >
|
|
|
+ <div style="margin-bottom: 20px;">
|
|
|
+ <el-form :inline="true" @submit.prevent>
|
|
|
+ <el-form-item label="品牌名称:">
|
|
|
+ <el-input
|
|
|
+ v-model="brandSearchKeyword"
|
|
|
+ placeholder="请输入品牌名称"
|
|
|
+ style="width: 200px;"
|
|
|
+ @keyup.enter="handleSearchBrand"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" @click="handleSearchBrand" :loading="brandSearchLoading">搜索</el-button>
|
|
|
+ <el-button type="primary" @click="handleAddBrandToList()">添加</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 搜索结果列表 -->
|
|
|
+ <div v-if="brandSearchResults.length > 0" class="brand-search-results">
|
|
|
+ <div class="search-results-title">搜索结果:</div>
|
|
|
+ <div class="brand-result-item"
|
|
|
+ v-for="brand in brandSearchResults"
|
|
|
+ :key="brand.id"
|
|
|
+ @click="handleAddBrandToList(brand)"
|
|
|
+ >
|
|
|
+ <span class="brand-result-name">{{ brand.brandName }}</span>
|
|
|
+ <span class="brand-result-no">编号: {{ brand.brandNo }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="selected-brands-section">
|
|
|
+ <div class="section-label">已选择品牌:</div>
|
|
|
+ <div class="brand-tags-container">
|
|
|
+ <el-tag
|
|
|
+ v-for="brand in tempSelectedBrands"
|
|
|
+ :key="brand.id"
|
|
|
+ closable
|
|
|
+ @close="handleRemoveTempBrand(brand)"
|
|
|
+ type="info"
|
|
|
+ style="margin-right: 10px; margin-bottom: 10px;"
|
|
|
+ >
|
|
|
+ {{ brand.brandName }}
|
|
|
+ </el-tag>
|
|
|
+ <span v-if="tempSelectedBrands.length === 0" style="color: #999; font-size: 14px;">暂无已选择品牌</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="handleBrandDialogClose">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleBrandSubmit" :loading="brandSubmitLoading">保存</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, onMounted } from 'vue';
|
|
|
+import { useRoute, useRouter } from 'vue-router';
|
|
|
+import { ArrowLeft, Plus, Search } from '@element-plus/icons-vue';
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
+import { useUserStore } from '@/store/modules/user';
|
|
|
+import FileSelector from '@/components/FileSelector/index.vue';
|
|
|
+import FileUpload from '@/components/FileUpload/index.vue';
|
|
|
+import { getInfo, addInfo, updateInfo, getStaffListSplice, getSupplierStaffIds, getContactListById, getSupplierCategories, getSupplierContractsById, getBankBySupplierId, getAuthorizeDetailList, savePurchaseInfo, getDictData, getTaxRateList, getSettlementMethodList, getInvoiceTypeList, listInfo } from '@/api/supplier/info';
|
|
|
+import { getBank, updateBank, addBank } from '@/api/supplier/bank';
|
|
|
+import { BankForm } from '@/api/supplier/bank/types';
|
|
|
+import { getContact, addContact, updateContact, getSupplierContactlistById } from '@/api/supplier/contact';
|
|
|
+import { ContactForm } from '@/api/supplier/contact/types';
|
|
|
+import { InfoVO } from '@/api/supplier/info/types';
|
|
|
+import { listCompany } from '@/api/company/company';
|
|
|
+import { CompanyVO } from '@/api/company/company/types';
|
|
|
+import { listEnterpriseScale } from '@/api/supplier/customerCategory/enterpriseScale';
|
|
|
+import { EnterpriseScaleVO } from '@/api/supplier/customerCategory/enterpriseScale/types';
|
|
|
+import { listIndustryCategory } from '@/api/supplier/customerCategory/industryCategory';
|
|
|
+import { IndustryCategoryVO } from '@/api/supplier/customerCategory/industryCategory/types';
|
|
|
+import { listLevel } from '@/api/system/level';
|
|
|
+import { LevelVO } from '@/api/system/level/types';
|
|
|
+import { listType } from '@/api/system/type';
|
|
|
+import { TypeVO } from '@/api/system/type/types';
|
|
|
+import { listBrand, getBrand } from '@/api/product/brand';
|
|
|
+import { BrandVO } from '@/api/product/brand/types';
|
|
|
+import { getProductCategoryList } from '@/api/product/category';
|
|
|
+import { listAddress, getAddress, addAddress, updateAddress, delAddress } from '@/api/supplier/address';
|
|
|
+import { AddressForm, AddressQuery } from '@/api/supplier/address/types';
|
|
|
+import { addArea, listArea, getArea } from '@/api/supplier/area';
|
|
|
+import { listContract, getContract, addContract, updateContract } from '@/api/supplier/contract';
|
|
|
+import { ContractForm } from '@/api/supplier/contract/types';
|
|
|
+import { getBusinessInformation } from '@/api/supplier/businessInfo';
|
|
|
+import { regionData } from 'element-china-area-data';
|
|
|
+import { chinaAreaList } from '@/api/system/addressarea/index';
|
|
|
+import { listInvoiceType } from '@/api/system/invoiceType';
|
|
|
+import { InvoiceTypeVO } from '@/api/system/invoiceType/types';
|
|
|
+import { listBank as listSystemBank } from '@/api/system/bank';
|
|
|
+import { BankVO as SystemBankVO } from '@/api/system/bank/types';
|
|
|
+import { listByIds } from '@/api/system/oss';
|
|
|
+
|
|
|
+const route = useRoute();
|
|
|
+const router = useRouter();
|
|
|
+const userStore = useUserStore();
|
|
|
+
|
|
|
+const activeTab = ref('basic');
|
|
|
+const isAddMode = ref(false); // 是否为新增模式
|
|
|
+const isBasicInfoSaved = ref(false); // 基础信息是否已保存
|
|
|
+const currentSupplierId = ref<string | number | null>(null); // 当前登录用户所属的供应商ID
|
|
|
+const detailData = ref<InfoVO>({} as InfoVO);
|
|
|
+const staffOptions = ref<any[]>([]);
|
|
|
+const selectedProductManager = ref<number | null>(null);
|
|
|
+const selectedBuyer = ref<number | null>(null);
|
|
|
+const companyOptions = ref<CompanyVO[]>([]);
|
|
|
+const enterpriseScaleOptions = ref<EnterpriseScaleVO[]>([]);
|
|
|
+const industryCategoryOptions = ref<IndustryCategoryVO[]>([]);
|
|
|
+const supplierLevelOptions = ref<LevelVO[]>([]);
|
|
|
+const supplierTypeOptions = ref<TypeVO[]>([]);
|
|
|
+
|
|
|
+// 工商信息对象
|
|
|
+const businessInfo = ref<any>({});
|
|
|
+const businessInfoLoading = ref(false); // 获取工商信息的loading状态
|
|
|
+
|
|
|
+// 文件选择器相关
|
|
|
+const businessLicenseDialogVisible = ref(false);
|
|
|
+const personImageDialogVisible = ref(false);
|
|
|
+
|
|
|
+// 联系人相关数据
|
|
|
+const contactList = ref<any[]>([]);
|
|
|
+const contactLoading = ref(false);
|
|
|
+const contactSearchParams = ref({
|
|
|
+ userNo: '',
|
|
|
+ userName: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 联系人对话框相关
|
|
|
+const contactDialogVisible = ref(false);
|
|
|
+const contactDialogTitle = ref('');
|
|
|
+const contactDialogReadonly = ref(false);
|
|
|
+const contactFormRef = ref<ElFormInstance>();
|
|
|
+const contactSubmitLoading = ref(false);
|
|
|
+const contactForm = ref<ContactForm>({
|
|
|
+ supplierNo: '',
|
|
|
+ supplierId: undefined,
|
|
|
+ userNo: '',
|
|
|
+ userName: '',
|
|
|
+ phone: '',
|
|
|
+ roleNo: '',
|
|
|
+ departmentNo: '',
|
|
|
+ position: '',
|
|
|
+ isPrimaryContact: '0',
|
|
|
+ isRegister: '0',
|
|
|
+ email: '',
|
|
|
+ fax: '',
|
|
|
+ remark: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 联系人表单验证规则
|
|
|
+const contactFormRules = {
|
|
|
+ userName: [{ required: true, message: '请输入员工姓名', trigger: 'blur' }],
|
|
|
+ phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }]
|
|
|
+};
|
|
|
+
|
|
|
+// 供应信息相关数据
|
|
|
+const productCategoryList = ref<any[]>([]);
|
|
|
+const selectedCategories = ref<string[]>([]);
|
|
|
+const supplyAreaList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 授权详情信息列表
|
|
|
+const authorizationList = ref<any[]>([]);
|
|
|
+const authorizationPagination = ref({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+
|
|
|
+// 供货区域对话框相关
|
|
|
+const supplyAreaDialogVisible = ref(false);
|
|
|
+const supplyAreaSubmitLoading = ref(false);
|
|
|
+const selectedSupplyAreas = ref<any[]>([]); // 选中的供货区域(级联选择器的值)
|
|
|
+const supplyAreaOptions = ref<any[]>([]); // 供货区域选项(从接口获取)
|
|
|
+const savedAreaData = ref<any[]>([]); // 已保存的供货区域数据
|
|
|
+const cascaderProps = {
|
|
|
+ multiple: true,
|
|
|
+ checkStrictly: true, // 改为 true,允许选择任意级别
|
|
|
+ value: 'areaCode',
|
|
|
+ label: 'areaName',
|
|
|
+ children: 'children',
|
|
|
+ emitPath: true
|
|
|
+};
|
|
|
+
|
|
|
+// 省市区级联选择器的 props 配置
|
|
|
+const regionCascaderProps = {
|
|
|
+ value: 'value',
|
|
|
+ label: 'label',
|
|
|
+ children: 'children',
|
|
|
+ emitPath: true
|
|
|
+};
|
|
|
+
|
|
|
+// 详细地址级联选择器相关
|
|
|
+const regionOptions = ref<any[]>([]); // 省市区级联选择器选项
|
|
|
+const selectedOfficeRegion = ref<string[]>([]); // 选中的省市区代码数组
|
|
|
+
|
|
|
+// 品牌相关数据
|
|
|
+const selectedBrands = ref<BrandVO[]>([]); // 已选择的品牌列表
|
|
|
+const brandDialogVisible = ref(false);
|
|
|
+const brandSearchKeyword = ref(''); // 品牌搜索关键词
|
|
|
+const tempSelectedBrands = ref<BrandVO[]>([]); // 弹框中临时选择的品牌
|
|
|
+const brandSearchResults = ref<BrandVO[]>([]); // 品牌搜索结果
|
|
|
+const allBrandList = ref<BrandVO[]>([]); // 所有品牌列表
|
|
|
+const brandSubmitLoading = ref(false);
|
|
|
+const brandSearchLoading = ref(false);
|
|
|
+
|
|
|
+/** 获取授权详情列表 */
|
|
|
+const getAuthorizationList = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await getAuthorizeDetailList({
|
|
|
+ supplierId: id,
|
|
|
+ pageNum: authorizationPagination.value.pageNum,
|
|
|
+ pageSize: authorizationPagination.value.pageSize
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('授权详情API返回:', res);
|
|
|
+
|
|
|
+ authorizationList.value = res.rows || res.data || [];
|
|
|
+ authorizationPagination.value.total = res.total || authorizationList.value.length;
|
|
|
+
|
|
|
+ console.log('授权详情列表:', authorizationList.value);
|
|
|
+ console.log('分页信息:', authorizationPagination.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取授权详情列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 地址管理列表
|
|
|
+const addressList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 地址管理对话框相关
|
|
|
+const addressDialogVisible = ref(false);
|
|
|
+const addressDialogTitle = ref('');
|
|
|
+const addressDialogReadonly = ref(false);
|
|
|
+const addressFormRef = ref<ElFormInstance>();
|
|
|
+const addressSubmitLoading = ref(false);
|
|
|
+const selectedAddressRegion = ref<string[]>([]); // 地址的省市区代码数组
|
|
|
+const addressForm = ref<AddressForm>({
|
|
|
+ supplierNo: '',
|
|
|
+ supplierId: undefined,
|
|
|
+ shipperName: '',
|
|
|
+ shipperPhone: '',
|
|
|
+ shippingPostCode: '',
|
|
|
+ shippingProvincial: '',
|
|
|
+ shippingCity: '',
|
|
|
+ shippingCounty: '',
|
|
|
+ shippingAddress: '',
|
|
|
+ isSelf: 0
|
|
|
+});
|
|
|
+
|
|
|
+// 地址表单验证规则
|
|
|
+const addressFormRules = {
|
|
|
+ shipperName: [{ required: true, message: '请输入收货人', trigger: 'blur' }],
|
|
|
+ shipperPhone: [{ required: true, message: '请输入手机号码', trigger: 'blur' }],
|
|
|
+ shippingProvincial: [{ required: true, message: '请选择地址', trigger: 'change' }]
|
|
|
+};
|
|
|
+
|
|
|
+// 付款信息列表
|
|
|
+const paymentInfoList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 付款信息对话框相关
|
|
|
+const paymentDialogVisible = ref(false);
|
|
|
+const paymentDialogTitle = ref('');
|
|
|
+const paymentDialogReadonly = ref(false);
|
|
|
+const paymentFormRef = ref<ElFormInstance>();
|
|
|
+const paymentSubmitLoading = ref(false);
|
|
|
+const paymentForm = ref<BankForm>({
|
|
|
+ num: undefined,
|
|
|
+ supplierNo: '',
|
|
|
+ bankNum: '',
|
|
|
+ bankInfoNo: undefined,
|
|
|
+ bankName: '',
|
|
|
+ bankNo: '',
|
|
|
+ isture: '1',
|
|
|
+ circlesName: '',
|
|
|
+ phone: '',
|
|
|
+ invoiceTypeNo: undefined,
|
|
|
+ invoiceTypeName: '',
|
|
|
+ businessName: '',
|
|
|
+ businessAddress: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 发票类型列表和银行列表
|
|
|
+const invoiceTypeList = ref<InvoiceTypeVO[]>([]);
|
|
|
+const systemBankList = ref<SystemBankVO[]>([]);
|
|
|
+
|
|
|
+// 付款信息表单验证规则
|
|
|
+const paymentFormRules = {
|
|
|
+ invoiceTypeNo: [{ required: true, message: '请选择开票类型', trigger: 'change' }],
|
|
|
+ bankNum: [{ required: true, message: '请输入开户行行号', trigger: 'blur' }],
|
|
|
+ bankInfoNo: [{ required: true, message: '请选择开户行名称', trigger: 'change' }],
|
|
|
+ bankNo: [{ required: true, message: '请输入银行账户', trigger: 'blur' }],
|
|
|
+ phone: [{ required: true, message: '请输入固定电话', trigger: 'blur' }],
|
|
|
+ num: [{ required: true, message: '请选择是否主账号', trigger: 'change' }]
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取发票类型列表 */
|
|
|
+const getInvoiceTypeData = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listInvoiceType({ pageNum: 1, pageSize: 1000 });
|
|
|
+ invoiceTypeList.value = res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取发票类型失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取银行列表 */
|
|
|
+const getSystemBankData = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listSystemBank({ pageNum: 1, pageSize: 1000 });
|
|
|
+ systemBankList.value = res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取银行列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取付款信息 */
|
|
|
+/** 获取付款信息 */
|
|
|
+const getPaymentInfo = async () => {
|
|
|
+ // 优先使用 URL 中的 id,如果没有则使用 userStore.supplierId
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!id) {
|
|
|
+ console.warn('无法获取付款信息:缺少供应商ID');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ console.log('获取付款信息,供应商ID:', id);
|
|
|
+ const res = await getBankBySupplierId(id);
|
|
|
+ // 后端返回数组
|
|
|
+ if (res.data) {
|
|
|
+ paymentInfoList.value = Array.isArray(res.data) ? res.data : [res.data];
|
|
|
+ console.log('付款信息列表:', paymentInfoList.value);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取付款信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 合同管理相关数据
|
|
|
+const contractList = ref<any[]>([]);
|
|
|
+const contractSearchParams = ref({
|
|
|
+ contractNo: '',
|
|
|
+ contractName: '',
|
|
|
+ contractType: '',
|
|
|
+ contractStartTime: '' as string | Date | '',
|
|
|
+ contractEndTime: '' as string | Date | '',
|
|
|
+ contractStatus: ''
|
|
|
+});
|
|
|
+const contractPagination = ref({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+
|
|
|
+// 合同对话框相关
|
|
|
+const contractDialogVisible = ref(false);
|
|
|
+const contractDialogTitle = ref('');
|
|
|
+const contractDialogReadonly = ref(false);
|
|
|
+const contractFormRef = ref<ElFormInstance>();
|
|
|
+const contractSubmitLoading = ref(false);
|
|
|
+const contractTypeDict = ref<any[]>([]); // 合同类型字典
|
|
|
+const taxRateList = ref<any[]>([]); // 税率列表
|
|
|
+const settlementMethodList = ref<any[]>([]); // 结算方式列表
|
|
|
+const contractForm = ref<ContractForm>({
|
|
|
+ supplierNo: '',
|
|
|
+ supplierId: undefined,
|
|
|
+ contractNo: '',
|
|
|
+ contractName: '',
|
|
|
+ contractType: '',
|
|
|
+ contractStartTime: '',
|
|
|
+ contractEndTime: '',
|
|
|
+ contractStatus: 0,
|
|
|
+ demandReminderTime: 4,
|
|
|
+ taxRate: undefined,
|
|
|
+ contractAmount: undefined,
|
|
|
+ contractDescription: '',
|
|
|
+ contractAttachment: '',
|
|
|
+ settlementMethod: '',
|
|
|
+ invoiceType: ''
|
|
|
+});
|
|
|
+
|
|
|
+// 合同表单验证规则
|
|
|
+const contractFormRules = {
|
|
|
+ contractName: [{ required: true, message: '请输入合同名称', trigger: 'blur' }],
|
|
|
+ contractType: [{ required: true, message: '请选择合同类型', trigger: 'change' }],
|
|
|
+ contractStartTime: [{ required: true, message: '请选择开始时间', trigger: 'change' }],
|
|
|
+ contractEndTime: [{ required: true, message: '请选择截止时间', trigger: 'change' }]
|
|
|
+};
|
|
|
+
|
|
|
+/** 返回列表页 */
|
|
|
+const goBack = () => {
|
|
|
+ // 使用浏览器后退,返回上一页
|
|
|
+ router.back();
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取当前登录用户的供应商ID */
|
|
|
+const getCurrentUserSupplier = async () => {
|
|
|
+ try {
|
|
|
+ // 确保用户信息已加载(包括供应商信息)
|
|
|
+ if (!userStore.supplierId) {
|
|
|
+ console.log('供应商信息未加载,正在加载...');
|
|
|
+ await userStore.getInfo();
|
|
|
+ }
|
|
|
+
|
|
|
+ const storeSupplierId = userStore.supplierId;
|
|
|
+
|
|
|
+ if (!storeSupplierId) {
|
|
|
+ console.warn('未获取到供应商ID');
|
|
|
+ ElMessage.warning('当前用户未配置供应商信息,请联系管理员');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('✓ 从 userStore 获取到供应商ID:', storeSupplierId);
|
|
|
+ console.log('供应商编号:', userStore.supplierNo);
|
|
|
+ console.log('联系人信息:', userStore.contactInfo);
|
|
|
+
|
|
|
+ // 保存到本地变量
|
|
|
+ currentSupplierId.value = storeSupplierId;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('✗ 获取供应商信息失败:', e);
|
|
|
+ ElMessage.error('获取供应商信息失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取工商信息 */
|
|
|
+const handleGetBusinessInfo = async () => {
|
|
|
+ if (!detailData.value.enterpriseName) {
|
|
|
+ ElMessage.warning('请先输入企业名称');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ businessInfoLoading.value = true;
|
|
|
+
|
|
|
+ // 调用获取工商信息接口
|
|
|
+ const res = await getBusinessInformation(detailData.value.enterpriseName);
|
|
|
+
|
|
|
+ if (res.code === 200 && res.data) {
|
|
|
+ // 将获取到的工商信息填充到表单
|
|
|
+ businessInfo.value = res.data;
|
|
|
+
|
|
|
+ // 自动填充基本信息表单的相关字段
|
|
|
+ if (res.data.businessName) {
|
|
|
+ detailData.value.businessName = res.data.businessName;
|
|
|
+ }
|
|
|
+ if (res.data.socialCreditCode) {
|
|
|
+ detailData.value.socialCreditCode = res.data.socialCreditCode;
|
|
|
+ }
|
|
|
+ if (res.data.legalPersonName) {
|
|
|
+ detailData.value.legalPersonName = res.data.legalPersonName;
|
|
|
+ }
|
|
|
+ if (res.data.registeredCapital) {
|
|
|
+ detailData.value.registeredCapital = res.data.registeredCapital;
|
|
|
+ }
|
|
|
+
|
|
|
+ ElMessage({ message: '工商信息获取成功', type: 'info' });
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg || '获取工商信息失败');
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取工商信息失败:', e);
|
|
|
+ ElMessage.error('获取工商信息失败');
|
|
|
+ } finally {
|
|
|
+ businessInfoLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 保存数据 */
|
|
|
+const handleSave = async () => {
|
|
|
+ try {
|
|
|
+ // 验证企业简称必填
|
|
|
+ if (!detailData.value.shortName) {
|
|
|
+ ElMessage.warning('请输入企业简称');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取供应商ID
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) {
|
|
|
+ ElMessage.error('供应商ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 只传递 id 和 shortName
|
|
|
+ const submitData = {
|
|
|
+ id: id,
|
|
|
+ shortName: detailData.value.shortName
|
|
|
+ };
|
|
|
+
|
|
|
+ // 调用更新接口
|
|
|
+ await updateInfo(submitData as any);
|
|
|
+ ElMessage({ message: '保存成功', type: 'info' });
|
|
|
+
|
|
|
+ // 刷新当前数据
|
|
|
+ await getDetail();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存失败:', e);
|
|
|
+ ElMessage.error('保存失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 打开营业执照选择对话框 */
|
|
|
+const openBusinessLicenseSelector = () => {
|
|
|
+ businessLicenseDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 打开法人身份证照片选择对话框 */
|
|
|
+const openPersonImageSelector = () => {
|
|
|
+ personImageDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 营业执照选择确认 */
|
|
|
+const handleBusinessLicenseConfirm = (files: any[]) => {
|
|
|
+ if (files && files.length > 0) {
|
|
|
+ const file = files[0];
|
|
|
+ detailData.value.businessLicense = file.url || file.fileUrl;
|
|
|
+ console.log('选择的营业执照:', file);
|
|
|
+ ElMessage({ message: '营业执照选择成功', type: 'info' });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 法人身份证照片选择确认 */
|
|
|
+const handlePersonImageConfirm = (files: any[]) => {
|
|
|
+ if (files && files.length > 0) {
|
|
|
+ const file = files[0];
|
|
|
+ // 保存图片URL路径,不是ID
|
|
|
+ detailData.value.personImage = file.url || file.fileUrl;
|
|
|
+ detailData.value.personImageUrl = file.url || file.fileUrl;
|
|
|
+ console.log('选择的法人身份证照片:', file);
|
|
|
+ ElMessage({ message: '法人身份证照片选择成功', type: 'info' });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 初始化省市区级联选择器数据 */
|
|
|
+const initRegionOptions = async () => {
|
|
|
+ try {
|
|
|
+ // 使用 element-china-area-data 提供的地区数据
|
|
|
+ regionOptions.value = regionData;
|
|
|
+ console.log('省市区数据加载完成:', regionOptions.value.length);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('初始化省市区数据失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 初始化供货区域选项数据 */
|
|
|
+const initSupplyAreaOptions = async () => {
|
|
|
+ try {
|
|
|
+ // 供货区域仍使用原来的 API 数据结构,因为涉及到复杂的后端逻辑
|
|
|
+ const res = await chinaAreaList();
|
|
|
+ supplyAreaOptions.value = res.data || [];
|
|
|
+ console.log('供货区域选项数据加载完成:', supplyAreaOptions.value.length);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取供货区域数据失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 详细地址省市区改变事件 */
|
|
|
+const handleOfficeRegionChange = (value: string[]) => {
|
|
|
+ if (value && value.length === 3) {
|
|
|
+ // value 是 [省代码, 市代码, 区代码]
|
|
|
+ const [provinceCode, cityCode, districtCode] = value;
|
|
|
+
|
|
|
+ // 从 regionOptions 中查找对应的名称
|
|
|
+ let provinceName = '';
|
|
|
+ let cityName = '';
|
|
|
+ let districtName = '';
|
|
|
+
|
|
|
+ const province = regionOptions.value.find((p: any) => p.value === provinceCode);
|
|
|
+ if (province) {
|
|
|
+ provinceName = province.label;
|
|
|
+
|
|
|
+ const city = province.children?.find((c: any) => c.value === cityCode);
|
|
|
+ if (city) {
|
|
|
+ cityName = city.label;
|
|
|
+
|
|
|
+ const district = city.children?.find((d: any) => d.value === districtCode);
|
|
|
+ if (district) {
|
|
|
+ districtName = district.label;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新 detailData
|
|
|
+ detailData.value.officeProvince = provinceName;
|
|
|
+ detailData.value.officeCity = cityName;
|
|
|
+ detailData.value.officeCounty = districtName;
|
|
|
+ } else {
|
|
|
+ // 清空
|
|
|
+ detailData.value.officeProvince = '';
|
|
|
+ detailData.value.officeCity = '';
|
|
|
+ detailData.value.officeCounty = '';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取详情数据 */
|
|
|
+const getDetail = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ const mode = route.query.mode as string;
|
|
|
+
|
|
|
+ // 判断是否为新增模式
|
|
|
+ if (mode === 'add') {
|
|
|
+ isAddMode.value = true;
|
|
|
+ isBasicInfoSaved.value = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果 URL 中没有 id,从 userStore 获取 supplierId
|
|
|
+ if (!id) {
|
|
|
+ console.log('URL 中没有 id 参数,从 userStore 获取 supplierId');
|
|
|
+ console.log('当前 userStore.supplierId:', userStore.supplierId);
|
|
|
+
|
|
|
+ // 如果 userStore 中还没有 supplierId,尝试重新获取
|
|
|
+ if (!userStore.supplierId) {
|
|
|
+ console.log('userStore 中没有 supplierId,尝试重新获取...');
|
|
|
+ try {
|
|
|
+ await userStore.getSupplierInfo();
|
|
|
+ console.log('重新获取后的 supplierId:', userStore.supplierId);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取供应商信息失败:', error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ console.log('使用 userStore 中的 supplierId:', id);
|
|
|
+ } else {
|
|
|
+ console.warn('userStore 中也没有 supplierId,无法加载供应商信息');
|
|
|
+ ElMessage.warning('无法获取供应商信息,请重新登录');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 编辑模式,已有ID,视为基础信息已保存
|
|
|
+ isAddMode.value = false;
|
|
|
+ isBasicInfoSaved.value = true;
|
|
|
+
|
|
|
+ if (id) {
|
|
|
+ console.log('=== 准备调用 getInfo 接口 ===');
|
|
|
+ console.log('接口路径: /customer/info/' + id);
|
|
|
+ console.log('供应商ID:', id);
|
|
|
+ console.log('ID类型:', typeof id);
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await getInfo(id);
|
|
|
+ detailData.value = res.data;
|
|
|
+ console.log('✓ 成功获取供应商详情数据:', detailData.value);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('✗ 获取供应商详情失败:', error);
|
|
|
+ ElMessage.error('获取供应商详情失败: ' + (error as any)?.message || '未知错误');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果 personImageUrl 为空但 personImage 有值,使用 personImage 的值
|
|
|
+ if (!detailData.value.personImageUrl && detailData.value.personImage) {
|
|
|
+ detailData.value.personImageUrl = detailData.value.personImage;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化品牌列表
|
|
|
+ initBrandList();
|
|
|
+ // 初始化详细地址显示
|
|
|
+ if (detailData.value.officeProvince && detailData.value.officeCity && detailData.value.officeCounty) {
|
|
|
+ const province = detailData.value.officeProvince;
|
|
|
+ const city = detailData.value.officeCity;
|
|
|
+ const county = detailData.value.officeCounty;
|
|
|
+
|
|
|
+ // 根据省市区名称查找对应的代码
|
|
|
+ const provinceItem = regionOptions.value.find((p: any) => p.label === province);
|
|
|
+ if (provinceItem) {
|
|
|
+ const cityItem = provinceItem.children?.find((c: any) => c.label === city);
|
|
|
+ if (cityItem) {
|
|
|
+ const districtItem = cityItem.children?.find((d: any) => d.label === county);
|
|
|
+ if (districtItem) {
|
|
|
+ selectedOfficeRegion.value = [provinceItem.value, cityItem.value, districtItem.value];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析工商信息,支持 otherCustomersMap 或 otherCustomers
|
|
|
+ const otherCustomersData = (detailData.value as any).otherCustomersMap || detailData.value.otherCustomers;
|
|
|
+ if (otherCustomersData) {
|
|
|
+ try {
|
|
|
+ // 如果是字符串,需要解析JSON
|
|
|
+ if (typeof otherCustomersData === 'string') {
|
|
|
+ businessInfo.value = JSON.parse(otherCustomersData);
|
|
|
+ } else {
|
|
|
+ businessInfo.value = otherCustomersData;
|
|
|
+ }
|
|
|
+ console.log('工商信息:', businessInfo.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析工商信息失败:', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 工商信息字段已经在 detailData 中返回,直接使用
|
|
|
+ // 将 detailData 的工商信息字段映射到 businessInfo
|
|
|
+ businessInfo.value = {
|
|
|
+ businessName: detailData.value.businessName,
|
|
|
+ registrationAuthority: (detailData.value as any).registrationAuthority,
|
|
|
+ establishmentDate: (detailData.value as any).establishmentDate,
|
|
|
+ registrationStatus: (detailData.value as any).registrationStatus,
|
|
|
+ paidInCapital: (detailData.value as any).paidInCapital,
|
|
|
+ socialCreditCode: detailData.value.socialCreditCode,
|
|
|
+ legalPersonName: detailData.value.legalPersonName,
|
|
|
+ registeredCapital: detailData.value.registeredCapital,
|
|
|
+ revocationDate: (detailData.value as any).revocationDate,
|
|
|
+ bussinessRange: (detailData.value as any).bussinessRange,
|
|
|
+ businessAddress: (detailData.value as any).businessAddress
|
|
|
+ };
|
|
|
+ console.log('工商信息(从详情接口):', businessInfo.value);
|
|
|
+
|
|
|
+ // 获取当前供应商的产品经理和采购员ID
|
|
|
+ try {
|
|
|
+ const staffIdsRes = await getSupplierStaffIds(id);
|
|
|
+ const staffIds = staffIdsRes.data; // {productManager: 1, purchaser: 2}
|
|
|
+
|
|
|
+ selectedProductManager.value = staffIds.productManager;
|
|
|
+ selectedBuyer.value = staffIds.purchaser;
|
|
|
+
|
|
|
+ console.log('当前产品经理ID:', staffIds.productManager);
|
|
|
+ console.log('当前采购员ID:', staffIds.purchaser);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取人员ID失败:', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取人员下拉选项 */
|
|
|
+const getStaffOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getStaffListSplice();
|
|
|
+ const staffMap = res.data; // Map<Long, String> 格式:{1: "00040,郑春风", 2: "00050,王坤"}
|
|
|
+
|
|
|
+ // 转换为下拉框选项格式
|
|
|
+ staffOptions.value = Object.entries(staffMap).map(([staffId, displayText]) => ({
|
|
|
+ staffId: Number(staffId),
|
|
|
+ displayText: displayText,
|
|
|
+ label: displayText,
|
|
|
+ value: Number(staffId)
|
|
|
+ }));
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取人员信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取公司下拉选项 */
|
|
|
+const getCompanyOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listCompany({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000,
|
|
|
+ status: '0'
|
|
|
+ }); // 只获取正常状态的公司
|
|
|
+ companyOptions.value = res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取公司信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取企业规模下拉选项 */
|
|
|
+const getEnterpriseScaleOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listEnterpriseScale({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000,
|
|
|
+ status: '0' // 只获取正常状态的企业规模
|
|
|
+ });
|
|
|
+ enterpriseScaleOptions.value = res.data || res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取企业规模信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取行业类别下拉选项 */
|
|
|
+const getIndustryCategoryOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listIndustryCategory({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000,
|
|
|
+ status: '0' // 只获取正常状态的行业类别
|
|
|
+ });
|
|
|
+ industryCategoryOptions.value = res.data || res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取行业类别信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取供应商等级下拉选项 */
|
|
|
+const getSupplierLevelOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listLevel({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+ supplierLevelOptions.value = res.data || res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取供应商等级信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取供应商类型下拉选项 */
|
|
|
+const getSupplierTypeOptions = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listType({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ } as any);
|
|
|
+ supplierTypeOptions.value = res.data || res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取供应商类型信息失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取联系人列表 */
|
|
|
+const getContactList = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ contactLoading.value = true;
|
|
|
+ try {
|
|
|
+ const res = await getContactListById(id, {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 100,
|
|
|
+ ...contactSearchParams.value
|
|
|
+ });
|
|
|
+ contactList.value = res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取联系人列表失败:', e);
|
|
|
+ } finally {
|
|
|
+ contactLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索联系人 */
|
|
|
+const handleContactSearch = () => {
|
|
|
+ getContactList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 重置联系人搜索 */
|
|
|
+const handleContactReset = () => {
|
|
|
+ contactSearchParams.value = {
|
|
|
+ userNo: '',
|
|
|
+ userName: ''
|
|
|
+ };
|
|
|
+ getContactList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增联系人 */
|
|
|
+const handleAddContact = () => {
|
|
|
+ // 重置表单
|
|
|
+ contactForm.value = {
|
|
|
+ supplierNo: detailData.value.supplierNo,
|
|
|
+ supplierId: route.query.id as any,
|
|
|
+ userNo: '',
|
|
|
+ userName: '',
|
|
|
+ phone: '',
|
|
|
+ roleNo: '',
|
|
|
+ departmentNo: '',
|
|
|
+ position: '',
|
|
|
+ isPrimaryContact: '0',
|
|
|
+ isRegister: '0',
|
|
|
+ email: '',
|
|
|
+ fax: '',
|
|
|
+ remark: ''
|
|
|
+ };
|
|
|
+ contactDialogTitle.value = '新增联系人';
|
|
|
+ contactDialogReadonly.value = false;
|
|
|
+ contactDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看联系人 */
|
|
|
+const handleViewContact = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getContact(row.id);
|
|
|
+ Object.assign(contactForm.value, res.data);
|
|
|
+ contactDialogTitle.value = '查看联系人';
|
|
|
+ contactDialogReadonly.value = true;
|
|
|
+ contactDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取联系人详情失败:', e);
|
|
|
+ ElMessage.error('获取联系人详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 编辑联系人 */
|
|
|
+const handleEditContact = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getContact(row.id);
|
|
|
+ Object.assign(contactForm.value, res.data);
|
|
|
+ contactDialogTitle.value = '编辑联系人';
|
|
|
+ contactDialogReadonly.value = false;
|
|
|
+ contactDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取联系人详情失败:', e);
|
|
|
+ ElMessage.error('获取联系人详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交联系人 */
|
|
|
+const handleContactSubmit = async () => {
|
|
|
+ if (!contactFormRef.value) return;
|
|
|
+
|
|
|
+ contactFormRef.value.validate(async (valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ contactSubmitLoading.value = true;
|
|
|
+
|
|
|
+ // 设置供应商编号和ID
|
|
|
+ if (!contactForm.value.supplierNo && detailData.value.supplierNo) {
|
|
|
+ contactForm.value.supplierNo = detailData.value.supplierNo;
|
|
|
+ }
|
|
|
+ if (!contactForm.value.supplierId && route.query.id) {
|
|
|
+ contactForm.value.supplierId = route.query.id as any;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((contactForm.value as any).id) {
|
|
|
+ // 更新
|
|
|
+ await updateContact(contactForm.value);
|
|
|
+ ElMessage({ message: '更新成功', type: 'info' });
|
|
|
+ } else {
|
|
|
+ // 新增
|
|
|
+ await addContact(contactForm.value);
|
|
|
+ ElMessage({ message: '新增成功', type: 'info' });
|
|
|
+ }
|
|
|
+
|
|
|
+ contactDialogVisible.value = false;
|
|
|
+ // 刷新联系人列表
|
|
|
+ await getContactList();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存联系人失败:', e);
|
|
|
+ ElMessage.error('保存联系人失败');
|
|
|
+ } finally {
|
|
|
+ contactSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取产品分类列表 */
|
|
|
+const getProductCategories = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getProductCategoryList();
|
|
|
+ productCategoryList.value = res.data || [];
|
|
|
+ console.log('产品分类列表:', productCategoryList.value);
|
|
|
+
|
|
|
+ // 获取分类列表后,再获取已选择的品目
|
|
|
+ await getSupplierSelectedCategories();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取产品分类失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取供应商已选择的品目 */
|
|
|
+const getSupplierSelectedCategories = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await getSupplierCategories(id);
|
|
|
+ // 确保数据类型一致,转换为字符串数组
|
|
|
+ selectedCategories.value = (res.data || []).map(String);
|
|
|
+ console.log('供应商已选择的品目ID:', selectedCategories.value);
|
|
|
+ console.log('产品分类列表:', productCategoryList.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取供应商品目失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 保存供货类目 */
|
|
|
+const handleSaveCategories = async () => {
|
|
|
+ try {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) {
|
|
|
+ ElMessage.error('供应商ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用更新接口,保存选中的品目
|
|
|
+ await updateInfo({
|
|
|
+ id: id,
|
|
|
+ operatingCategory: selectedCategories.value.join(',')
|
|
|
+ } as any);
|
|
|
+
|
|
|
+ ElMessage({ message: '保存成功', type: 'info' });
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存供货类目失败:', e);
|
|
|
+ ElMessage.error('保存失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 保存采购信息 */
|
|
|
+const handleSavePurchaseInfo = async () => {
|
|
|
+ try {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) {
|
|
|
+ ElMessage.error('供应商ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用保存采购信息接口
|
|
|
+ await savePurchaseInfo({
|
|
|
+ supplierId: id,
|
|
|
+ productManager: selectedProductManager.value,
|
|
|
+ purchaser: selectedBuyer.value
|
|
|
+ });
|
|
|
+
|
|
|
+ ElMessage({ message: '保存成功', type: 'info' });
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存采购信息失败:', e);
|
|
|
+ ElMessage.error('保存失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取所有品牌列表 */
|
|
|
+const getAllBrandList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await listBrand({
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000 // 获取所有品牌
|
|
|
+ });
|
|
|
+ allBrandList.value = res.rows || [];
|
|
|
+ console.log('品牌列表:', allBrandList.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取品牌列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增品牌 - 打开弹框 */
|
|
|
+const handleAddBrand = () => {
|
|
|
+ // 复制当前已选择的品牌到临时列表
|
|
|
+ tempSelectedBrands.value = [...selectedBrands.value];
|
|
|
+ brandSearchKeyword.value = '';
|
|
|
+ // 显示所有品牌作为初始搜索结果
|
|
|
+ brandSearchResults.value = [...allBrandList.value];
|
|
|
+ brandDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索品牌 */
|
|
|
+const handleSearchBrand = async () => {
|
|
|
+ // 如果搜索关键词为空,显示所有品牌
|
|
|
+ if (!brandSearchKeyword.value.trim()) {
|
|
|
+ brandSearchResults.value = [...allBrandList.value];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ brandSearchLoading.value = true;
|
|
|
+ const res = await listBrand({
|
|
|
+ brandName: brandSearchKeyword.value.trim(),
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 50
|
|
|
+ });
|
|
|
+ brandSearchResults.value = res.rows || [];
|
|
|
+
|
|
|
+ if (brandSearchResults.value.length === 0) {
|
|
|
+ ElMessage.info('未找到匹配的品牌');
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('搜索品牌失败:', e);
|
|
|
+ ElMessage.error('搜索品牌失败');
|
|
|
+ } finally {
|
|
|
+ brandSearchLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 添加品牌到列表 */
|
|
|
+const handleAddBrandToList = (brand?: BrandVO) => {
|
|
|
+ // 如果没有传入品牌,则使用搜索关键词手动创建
|
|
|
+ if (!brand) {
|
|
|
+ if (!brandSearchKeyword.value.trim()) {
|
|
|
+ ElMessage.warning('请输入品牌名称或先搜索品牌');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 手动创建品牌对象(临时方案)
|
|
|
+ brand = {
|
|
|
+ id: brandSearchKeyword.value.trim(),
|
|
|
+ brandName: brandSearchKeyword.value.trim()
|
|
|
+ } as BrandVO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查品牌是否已存在
|
|
|
+ const exists = tempSelectedBrands.value.some(b => b.id === brand!.id);
|
|
|
+
|
|
|
+ if (exists) {
|
|
|
+ ElMessage.warning('该品牌已添加');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加品牌到临时列表
|
|
|
+ tempSelectedBrands.value.push(brand);
|
|
|
+ brandSearchKeyword.value = ''; // 清空搜索框
|
|
|
+ brandSearchResults.value = []; // 清空搜索结果
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除临时品牌 */
|
|
|
+const handleRemoveTempBrand = (brand: BrandVO) => {
|
|
|
+ const index = tempSelectedBrands.value.findIndex(b => b.id === brand.id);
|
|
|
+ if (index > -1) {
|
|
|
+ tempSelectedBrands.value.splice(index, 1);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除已选择的品牌 */
|
|
|
+const handleRemoveBrand = async (brand: BrandVO) => {
|
|
|
+ const index = selectedBrands.value.findIndex(b => b.id === brand.id);
|
|
|
+ if (index > -1) {
|
|
|
+ selectedBrands.value.splice(index, 1);
|
|
|
+ // 立即保存到后端
|
|
|
+ await saveBrandsToServer();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 品牌对话框关闭 */
|
|
|
+const handleBrandDialogClose = () => {
|
|
|
+ brandDialogVisible.value = false;
|
|
|
+ brandSearchKeyword.value = '';
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交品牌 */
|
|
|
+const handleBrandSubmit = async () => {
|
|
|
+ try {
|
|
|
+ brandSubmitLoading.value = true;
|
|
|
+
|
|
|
+ // 更新主品牌列表
|
|
|
+ selectedBrands.value = [...tempSelectedBrands.value];
|
|
|
+
|
|
|
+ // 保存到服务器
|
|
|
+ await saveBrandsToServer();
|
|
|
+
|
|
|
+ ElMessage({ message: '保存成功', type: 'info' });
|
|
|
+ brandDialogVisible.value = false;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存品牌失败:', e);
|
|
|
+ ElMessage.error('保存失败');
|
|
|
+ } finally {
|
|
|
+ brandSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 保存品牌到服务器 */
|
|
|
+const saveBrandsToServer = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) {
|
|
|
+ ElMessage.error('供应商ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将品牌ID用逗号分隔保存
|
|
|
+ const brandIds = selectedBrands.value.map(brand => brand.id).join(',');
|
|
|
+
|
|
|
+ await updateInfo({
|
|
|
+ id: id,
|
|
|
+ operatingBrand: brandIds
|
|
|
+ } as any);
|
|
|
+};
|
|
|
+
|
|
|
+/** 初始化品牌列表 - 从后端数据解析 */
|
|
|
+const initBrandList = async () => {
|
|
|
+ if (detailData.value.operatingBrand) {
|
|
|
+ // 后端返回的是用逗号分隔的品牌ID
|
|
|
+ const brandIds = detailData.value.operatingBrand.split(',').filter(id => id.trim());
|
|
|
+
|
|
|
+ if (brandIds.length > 0) {
|
|
|
+ try {
|
|
|
+ // 根据品牌ID获取品牌详细信息
|
|
|
+ const brandPromises = brandIds.map(id => getBrand(id.trim()));
|
|
|
+ const brandResults = await Promise.allSettled(brandPromises);
|
|
|
+
|
|
|
+ selectedBrands.value = brandResults
|
|
|
+ .filter(result => result.status === 'fulfilled')
|
|
|
+ .map(result => (result as PromiseFulfilledResult<any>).value.data)
|
|
|
+ .filter(brand => brand); // 过滤掉空值
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取品牌详情失败:', e);
|
|
|
+ // 降级处理:如果获取品牌详情失败,使用ID作为显示名称
|
|
|
+ selectedBrands.value = brandIds.map(id => ({
|
|
|
+ id: id.trim(),
|
|
|
+ brandName: id.trim()
|
|
|
+ } as BrandVO));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取供货区域列表 */
|
|
|
+const getSupplyAreaList = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await listArea({
|
|
|
+ supplierId: id,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+
|
|
|
+ // 保存原始数据,用于编辑时回显
|
|
|
+ savedAreaData.value = res.data || res.rows || [];
|
|
|
+
|
|
|
+ // 处理返回的数据,按层级组织
|
|
|
+ const areaData = savedAreaData.value;
|
|
|
+
|
|
|
+ // 第一步:先收集所有省份
|
|
|
+ const provinceMap: any = {};
|
|
|
+ areaData.forEach((area: any) => {
|
|
|
+ if (area.level === '1' || area.level === 1) {
|
|
|
+ provinceMap[area.areaCode] = {
|
|
|
+ province: area.areaName,
|
|
|
+ city: ''
|
|
|
+ };
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 第二步:将城市添加到对应的省份
|
|
|
+ areaData.forEach((area: any) => {
|
|
|
+ if (area.level === '2' || area.level === 2) {
|
|
|
+ const parentCode = area.parentCode;
|
|
|
+ if (provinceMap[parentCode]) {
|
|
|
+ // 将城市添加到省份的城市列表中
|
|
|
+ if (provinceMap[parentCode].city) {
|
|
|
+ provinceMap[parentCode].city += ',' + area.areaName;
|
|
|
+ } else {
|
|
|
+ provinceMap[parentCode].city = area.areaName;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 转换为数组
|
|
|
+ supplyAreaList.value = Object.values(provinceMap).filter((item: any) =>
|
|
|
+ item.province || item.city
|
|
|
+ );
|
|
|
+
|
|
|
+ console.log('供货区域列表:', supplyAreaList.value);
|
|
|
+ console.log('保存的原始数据:', savedAreaData.value);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取供货区域列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 编辑供货区域 */
|
|
|
+const handleEditSupplyArea = async () => {
|
|
|
+ supplyAreaDialogVisible.value = true;
|
|
|
+
|
|
|
+ // 根据已保存的数据回显选中状态
|
|
|
+ if (savedAreaData.value && savedAreaData.value.length > 0) {
|
|
|
+ const selectedPaths: any[] = [];
|
|
|
+
|
|
|
+ // 遍历已保存的数据,构建级联选择器需要的路径格式
|
|
|
+ savedAreaData.value.forEach((area: any) => {
|
|
|
+ if (area.level === '2') {
|
|
|
+ // 市级数据,需要找到对应的省份
|
|
|
+ const province = savedAreaData.value.find((p: any) =>
|
|
|
+ p.level === '1' && p.areaCode === area.parentCode
|
|
|
+ );
|
|
|
+
|
|
|
+ if (province) {
|
|
|
+ // 构建路径 [省代码, 市代码]
|
|
|
+ selectedPaths.push([province.areaCode, area.areaCode]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ selectedSupplyAreas.value = selectedPaths;
|
|
|
+ console.log('回显的选中路径:', selectedPaths);
|
|
|
+ } else {
|
|
|
+ selectedSupplyAreas.value = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 将区域代码转换为级联路径 */
|
|
|
+const convertRegionCodesToPaths = (codes: string[]) => {
|
|
|
+ const paths: any[] = [];
|
|
|
+
|
|
|
+ codes.forEach(code => {
|
|
|
+ const path = findRegionPath(code, supplyAreaOptions.value);
|
|
|
+ if (path) {
|
|
|
+ paths.push(path);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return paths;
|
|
|
+};
|
|
|
+
|
|
|
+/** 在区域树中查找指定代码的完整路径(只到市级) */
|
|
|
+const findRegionPath = (targetCode: string, regions: any[], currentPath: string[] = []): string[] | null => {
|
|
|
+ for (const region of regions) {
|
|
|
+ const newPath = [...currentPath, region.areaCode];
|
|
|
+
|
|
|
+ // 如果找到目标代码,返回路径
|
|
|
+ if (region.areaCode === targetCode) {
|
|
|
+ return newPath;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有子节点,继续查找(只查找到市级,即两层)
|
|
|
+ if (region.children && region.children.length > 0 && newPath.length < 2) {
|
|
|
+ const found = findRegionPath(targetCode, region.children, newPath);
|
|
|
+ if (found) {
|
|
|
+ return found;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交供货区域 */
|
|
|
+const handleSupplyAreaSubmit = async () => {
|
|
|
+ try {
|
|
|
+ supplyAreaSubmitLoading.value = true;
|
|
|
+
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) {
|
|
|
+ ElMessage.error('供应商ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建 areaList 数组
|
|
|
+ const areaList = buildAreaList(selectedSupplyAreas.value);
|
|
|
+ console.log('构建的 areaList:', areaList);
|
|
|
+
|
|
|
+ // 从选中的路径中提取区域信息(用于显示)
|
|
|
+ const regionData = extractRegionData(selectedSupplyAreas.value);
|
|
|
+
|
|
|
+ // 保存区域代码(用于下次编辑时回显)
|
|
|
+ const regionCodes = regionData.districtCodes.join(',');
|
|
|
+
|
|
|
+ const submitData = {
|
|
|
+ supplierId: id,
|
|
|
+ supplyNo: detailData.value.supplierNo,
|
|
|
+ areaList: areaList, // 传递 areaList 数组
|
|
|
+ province: regionData.provinces,
|
|
|
+ city: regionData.cities,
|
|
|
+ supplyRegions: regionCodes
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log('提交的数据:', submitData);
|
|
|
+
|
|
|
+ await addArea(submitData as any);
|
|
|
+
|
|
|
+ // 更新本地数据
|
|
|
+ (detailData.value as any).province = regionData.provinces;
|
|
|
+ (detailData.value as any).city = regionData.cities;
|
|
|
+ (detailData.value as any).district = '';
|
|
|
+ (detailData.value as any).supplyRegions = regionCodes;
|
|
|
+
|
|
|
+ // 更新供货区域列表显示
|
|
|
+ supplyAreaList.value = [{
|
|
|
+ province: regionData.provinces,
|
|
|
+ city: regionData.cities,
|
|
|
+ district: ''
|
|
|
+ }];
|
|
|
+
|
|
|
+ ElMessage({ message: '保存成功', type: 'info' });
|
|
|
+ supplyAreaDialogVisible.value = false;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存供货区域失败:', e);
|
|
|
+ ElMessage.error('保存失败');
|
|
|
+ } finally {
|
|
|
+ supplyAreaSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 从级联选择器的值中提取区域数据 */
|
|
|
+const extractRegionData = (selectedPaths: any[]) => {
|
|
|
+ // 用于存储省-市的映射关系
|
|
|
+ const provinceMap = new Map<string, Set<string>>();
|
|
|
+ const cityCodes: string[] = [];
|
|
|
+
|
|
|
+ selectedPaths.forEach(path => {
|
|
|
+ if (Array.isArray(path) && path.length >= 2) {
|
|
|
+ const [provinceCode, cityCode] = path;
|
|
|
+
|
|
|
+ // 保存城市代码
|
|
|
+ if (cityCode) {
|
|
|
+ cityCodes.push(cityCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查找对应的名称
|
|
|
+ const provinceName = findRegionName(provinceCode, supplyAreaOptions.value);
|
|
|
+ const province = supplyAreaOptions.value.find(p => p.areaCode === provinceCode);
|
|
|
+ const cityName = province && cityCode ? findRegionName(cityCode, province.children || []) : '';
|
|
|
+
|
|
|
+ if (provinceName) {
|
|
|
+ if (!provinceMap.has(provinceName)) {
|
|
|
+ provinceMap.set(provinceName, new Set());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cityName) {
|
|
|
+ provinceMap.get(provinceName)!.add(cityName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成省份和城市字符串
|
|
|
+ const provinces: string[] = [];
|
|
|
+ const cities: string[] = [];
|
|
|
+
|
|
|
+ provinceMap.forEach((citySet, provinceName) => {
|
|
|
+ provinces.push(provinceName);
|
|
|
+ cities.push(Array.from(citySet).join(','));
|
|
|
+ });
|
|
|
+
|
|
|
+ return {
|
|
|
+ provinces: provinces.join(','),
|
|
|
+ cities: cities.join(';'),
|
|
|
+ districts: '', // 没有区县数据
|
|
|
+ districtCodes: cityCodes
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+/** 根据代码查找区域名称 */
|
|
|
+const findRegionName = (code: string, regions: any[]): string => {
|
|
|
+ const region = regions.find(r => r.areaCode === code);
|
|
|
+ return region ? region.areaName : '';
|
|
|
+};
|
|
|
+
|
|
|
+/** 构建 areaList 数组 */
|
|
|
+const buildAreaList = (selectedPaths: any[]) => {
|
|
|
+ const areaList: any[] = [];
|
|
|
+ const provinceMap = new Map<string, Set<string>>(); // 省份代码 -> 城市代码集合
|
|
|
+ const addedProvinces = new Set<string>(); // 已添加的省份
|
|
|
+
|
|
|
+ console.log('选中的路径:', selectedPaths);
|
|
|
+
|
|
|
+ // 第一步:收集所有选中的省份和城市
|
|
|
+ selectedPaths.forEach(path => {
|
|
|
+ if (Array.isArray(path)) {
|
|
|
+ const provinceCode = path[0];
|
|
|
+ const cityCode = path[1];
|
|
|
+
|
|
|
+ if (!provinceMap.has(provinceCode)) {
|
|
|
+ provinceMap.set(provinceCode, new Set());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有城市代码,添加到集合中
|
|
|
+ if (cityCode) {
|
|
|
+ provinceMap.get(provinceCode)!.add(cityCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log('省份映射:', Array.from(provinceMap.entries()));
|
|
|
+
|
|
|
+ // 第二步:构建 areaList 数组
|
|
|
+ provinceMap.forEach((cityCodes, provinceCode) => {
|
|
|
+ // 查找省份信息
|
|
|
+ const province = supplyAreaOptions.value.find(p => p.areaCode === provinceCode);
|
|
|
+
|
|
|
+ if (province) {
|
|
|
+ // 添加省份(每个省份只添加一次)
|
|
|
+ if (!addedProvinces.has(provinceCode)) {
|
|
|
+ areaList.push({
|
|
|
+ areaCode: province.areaCode,
|
|
|
+ areaName: province.areaName,
|
|
|
+ level: 1
|
|
|
+ });
|
|
|
+ addedProvinces.add(provinceCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加该省份下所有选中的城市
|
|
|
+ cityCodes.forEach(cityCode => {
|
|
|
+ const city = province.children?.find((c: any) => c.areaCode === cityCode);
|
|
|
+
|
|
|
+ if (city) {
|
|
|
+ areaList.push({
|
|
|
+ areaCode: city.areaCode,
|
|
|
+ areaName: city.areaName,
|
|
|
+ parentCode: province.areaCode, // 使用省份的 areaCode 作为 parentCode
|
|
|
+ level: 2
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return areaList;
|
|
|
+};
|
|
|
+
|
|
|
+/** 格式化日期 */
|
|
|
+const formatDate = (date: string | Date) => {
|
|
|
+ if (!date) return '-';
|
|
|
+ const d = new Date(date);
|
|
|
+ return d.toISOString().split('T')[0];
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取合同状态类型 */
|
|
|
+const getContractStatusType = (status: number) => {
|
|
|
+ const statusMap = {
|
|
|
+ 0: 'info', // 草稿
|
|
|
+ 1: 'success', // 已生效
|
|
|
+ 2: 'warning', // 已到期
|
|
|
+ 3: 'danger', // 已终止
|
|
|
+ 4: 'danger' // 已作废
|
|
|
+ };
|
|
|
+ return statusMap[status] || 'info';
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取合同状态文本 */
|
|
|
+const getContractStatusText = (status: number) => {
|
|
|
+ const statusMap = {
|
|
|
+ 0: '待审核',
|
|
|
+ 1: '生效',
|
|
|
+ 2: '失效'
|
|
|
+
|
|
|
+ };
|
|
|
+ return statusMap[status] || '未知';
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取合同类型文本 */
|
|
|
+const getContractTypeText = (type: string | number) => {
|
|
|
+ const typeMap = {
|
|
|
+ '0': '年度合作',
|
|
|
+ '1': '项目采购',
|
|
|
+ '2': '其他合作',
|
|
|
+ };
|
|
|
+ return typeMap[type] || '未知';
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取授权状态文本 */
|
|
|
+const getAuthorizedStatusText = (status: string) => {
|
|
|
+ const statusMap = {
|
|
|
+ '0': '待审核',
|
|
|
+ '1': '已通过',
|
|
|
+ '2': '已驳回'
|
|
|
+ };
|
|
|
+ return statusMap[status] || '未知';
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索合同 */
|
|
|
+const handleContractSearch = () => {
|
|
|
+ console.log('搜索合同:', contractSearchParams.value);
|
|
|
+ getContractList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 重置合同搜索 */
|
|
|
+const handleContractReset = () => {
|
|
|
+ contractSearchParams.value = {
|
|
|
+ contractNo: '',
|
|
|
+ contractName: '',
|
|
|
+ contractType: '',
|
|
|
+ contractStartTime: '',
|
|
|
+ contractEndTime: '',
|
|
|
+ contractStatus: ''
|
|
|
+ };
|
|
|
+ getContractList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取合同列表 */
|
|
|
+const getContractList = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 构建查询参数,排除日期字段
|
|
|
+ const { contractStartTime, contractEndTime, ...otherParams } = contractSearchParams.value;
|
|
|
+
|
|
|
+ const params: any = {
|
|
|
+ pageNum: contractPagination.value.pageNum,
|
|
|
+ pageSize: contractPagination.value.pageSize,
|
|
|
+ ...otherParams
|
|
|
+ };
|
|
|
+
|
|
|
+ // 如果有开始时间,格式化为 YYYY-MM-DD
|
|
|
+ if (contractStartTime) {
|
|
|
+ const date = new Date(contractStartTime);
|
|
|
+ params.contractStartTime = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有结束时间,格式化为 YYYY-MM-DD
|
|
|
+ if (contractEndTime) {
|
|
|
+ const date = new Date(contractEndTime);
|
|
|
+ params.contractEndTime = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('合同查询参数:', params); // 添加日志方便调试
|
|
|
+
|
|
|
+ const res = await getSupplierContractsById(id, params);
|
|
|
+ contractList.value = res.rows || [];
|
|
|
+ contractPagination.value.total = res.total || 0;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取合同列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看附件 */
|
|
|
+const handleViewAttachment = async (row: any) => {
|
|
|
+ if (!row.contractAttachment) {
|
|
|
+ ElMessage.warning('暂无附件可下载');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 通过文件ID获取文件信息
|
|
|
+ const res = await listByIds(row.contractAttachment);
|
|
|
+ if (res.data && res.data.length > 0) {
|
|
|
+ const file = res.data[0];
|
|
|
+
|
|
|
+ // 使用fetch获取文件并强制下载
|
|
|
+ const response = await fetch(file.url);
|
|
|
+ const blob = await response.blob();
|
|
|
+
|
|
|
+ // 创建下载链接
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = file.originalName || (row.contractName ? `${row.contractName}_合同附件` : '合同附件');
|
|
|
+ link.style.display = 'none';
|
|
|
+
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+
|
|
|
+ // 清理URL对象
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+
|
|
|
+ ElMessage({ message: '开始下载', type: 'info' });
|
|
|
+ } else {
|
|
|
+ ElMessage.warning('未找到附件文件');
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('下载附件失败:', e);
|
|
|
+ ElMessage.error('下载失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看合同 */
|
|
|
+const handleViewContract = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getContract(row.id);
|
|
|
+ Object.assign(contractForm.value, res.data);
|
|
|
+ contractDialogTitle.value = '查看合同';
|
|
|
+ contractDialogReadonly.value = true;
|
|
|
+ contractDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取合同详情失败:', e);
|
|
|
+ ElMessage.error('获取合同详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 编辑合同 */
|
|
|
+const handleEditContract = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getContract(row.id);
|
|
|
+ Object.assign(contractForm.value, res.data);
|
|
|
+ contractDialogTitle.value = '编辑合同';
|
|
|
+ contractDialogReadonly.value = false;
|
|
|
+ contractDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取合同详情失败:', e);
|
|
|
+ ElMessage.error('获取合同详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取合同类型字典 */
|
|
|
+const getContractTypeDict = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getDictData('contract_type');
|
|
|
+ contractTypeDict.value = res.data || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取合同类型字典失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取税率列表 */
|
|
|
+const getTaxRateData = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getTaxRateList();
|
|
|
+ taxRateList.value = res.rows || res.data || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取税率列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取结算方式列表 */
|
|
|
+const getSettlementMethodData = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getSettlementMethodList();
|
|
|
+ settlementMethodList.value = res.rows || res.data || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取结算方式列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增合同 */
|
|
|
+const handleAddContract = () => {
|
|
|
+ // 重置表单
|
|
|
+ contractForm.value = {
|
|
|
+ supplierNo: detailData.value.supplierNo,
|
|
|
+ supplierId: route.query.id as any,
|
|
|
+ contractNo: '',
|
|
|
+ contractName: '',
|
|
|
+ contractType: '',
|
|
|
+ contractStartTime: '',
|
|
|
+ contractEndTime: '',
|
|
|
+ contractStatus: 0,
|
|
|
+ demandReminderTime: 4,
|
|
|
+ taxRate: undefined,
|
|
|
+ contractAmount: undefined,
|
|
|
+ contractDescription: '',
|
|
|
+ contractAttachment: '',
|
|
|
+ settlementMethod: '',
|
|
|
+ invoiceType: ''
|
|
|
+ };
|
|
|
+ contractDialogTitle.value = '添加合同';
|
|
|
+ contractDialogReadonly.value = false;
|
|
|
+ contractDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交合同 */
|
|
|
+const handleContractSubmit = async () => {
|
|
|
+ if (!contractFormRef.value) return;
|
|
|
+
|
|
|
+ contractFormRef.value.validate(async (valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ contractSubmitLoading.value = true;
|
|
|
+
|
|
|
+ // 设置供应商编号和ID
|
|
|
+ if (!contractForm.value.supplierNo && detailData.value.supplierNo) {
|
|
|
+ contractForm.value.supplierNo = detailData.value.supplierNo;
|
|
|
+ }
|
|
|
+ if (!contractForm.value.supplierId && route.query.id) {
|
|
|
+ contractForm.value.supplierId = route.query.id as any;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((contractForm.value as any).id) {
|
|
|
+ // 更新
|
|
|
+ await updateContract(contractForm.value);
|
|
|
+ ElMessage({ message: '更新成功', type: 'info' });
|
|
|
+ } else {
|
|
|
+ // 新增
|
|
|
+ await addContract(contractForm.value);
|
|
|
+ ElMessage({ message: '新增成功', type: 'info' });
|
|
|
+ }
|
|
|
+
|
|
|
+ contractDialogVisible.value = false;
|
|
|
+ // 刷新合同列表
|
|
|
+ await getContractList();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存合同失败:', e);
|
|
|
+ ElMessage.error('保存合同失败');
|
|
|
+ } finally {
|
|
|
+ contractSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 分页大小改变 */
|
|
|
+const handleContractSizeChange = (size: number) => {
|
|
|
+ contractPagination.value.pageSize = size;
|
|
|
+ getContractList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 当前页改变 */
|
|
|
+const handleContractCurrentChange = (page: number) => {
|
|
|
+ contractPagination.value.pageNum = page;
|
|
|
+ getContractList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 授权详情分页大小改变 */
|
|
|
+const handleAuthorizationSizeChange = (size: number) => {
|
|
|
+ authorizationPagination.value.pageSize = size;
|
|
|
+ getAuthorizationList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 授权详情当前页改变 */
|
|
|
+const handleAuthorizationCurrentChange = (page: number) => {
|
|
|
+ authorizationPagination.value.pageNum = page;
|
|
|
+ getAuthorizationList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看付款信息 */
|
|
|
+const handleViewPayment = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getBank(row.id);
|
|
|
+ Object.assign(paymentForm.value, res.data);
|
|
|
+ paymentDialogTitle.value = '查看付款信息';
|
|
|
+ paymentDialogReadonly.value = true;
|
|
|
+ paymentDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取付款信息详情失败:', e);
|
|
|
+ ElMessage.error('获取付款信息详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 编辑付款信息 */
|
|
|
+const handleEditPayment = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getBank(row.id);
|
|
|
+ Object.assign(paymentForm.value, res.data);
|
|
|
+ // 从供应商详情中获取企业工商名称和工商地址
|
|
|
+ paymentForm.value.businessName = detailData.value.businessName || '';
|
|
|
+ paymentForm.value.businessAddress = detailData.value.businessAddress || '';
|
|
|
+ paymentDialogTitle.value = '编辑付款信息';
|
|
|
+ paymentDialogReadonly.value = false;
|
|
|
+ paymentDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取付款信息详情失败:', e);
|
|
|
+ ElMessage.error('获取付款信息详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增付款信息 */
|
|
|
+const handleAddPayment = () => {
|
|
|
+ // 检查是否已保存供应商基本信息
|
|
|
+ if (!detailData.value.id || !detailData.value.supplierNo) {
|
|
|
+ ElMessage.warning('请先保存供应商基本信息后再新增付款信息');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重置表单
|
|
|
+ paymentForm.value = {
|
|
|
+ num: undefined,
|
|
|
+ supplierNo: detailData.value.supplierNo,
|
|
|
+ supplierId: detailData.value.id,
|
|
|
+ bankNum: '',
|
|
|
+ bankInfoNo: undefined,
|
|
|
+ bankName: '',
|
|
|
+ bankNo: '',
|
|
|
+ isture: '1',
|
|
|
+ circlesName: '',
|
|
|
+ phone: '',
|
|
|
+ invoiceTypeNo: undefined,
|
|
|
+ invoiceTypeName: '',
|
|
|
+ businessName: detailData.value.businessName || '',
|
|
|
+ businessAddress: detailData.value.businessAddress || ''
|
|
|
+ };
|
|
|
+ paymentDialogTitle.value = '新增付款信息';
|
|
|
+ paymentDialogReadonly.value = false;
|
|
|
+ paymentDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 发票类型选择改变 */
|
|
|
+const handleInvoiceTypeChange = (value: string | number) => {
|
|
|
+ const selectedInvoice = invoiceTypeList.value.find(item => item.id === value);
|
|
|
+ if (selectedInvoice) {
|
|
|
+ paymentForm.value.invoiceTypeNo = selectedInvoice.id;
|
|
|
+ paymentForm.value.invoiceTypeName = selectedInvoice.invoiceTypeName;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 银行选择改变 */
|
|
|
+const handleBankChange = (value: string | number) => {
|
|
|
+ const selectedBank = systemBankList.value.find(item => item.id === value);
|
|
|
+ if (selectedBank) {
|
|
|
+ paymentForm.value.bankInfoNo = selectedBank.id;
|
|
|
+ paymentForm.value.bankName = selectedBank.bnName;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交付款信息 */
|
|
|
+const handlePaymentSubmit = async () => {
|
|
|
+ if (!paymentFormRef.value) return;
|
|
|
+
|
|
|
+ paymentFormRef.value.validate(async (valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ paymentSubmitLoading.value = true;
|
|
|
+
|
|
|
+ // 设置供应商编号和ID
|
|
|
+ if (!paymentForm.value.supplierNo && detailData.value.supplierNo) {
|
|
|
+ paymentForm.value.supplierNo = detailData.value.supplierNo;
|
|
|
+ }
|
|
|
+ if (!paymentForm.value.supplierId && detailData.value.id) {
|
|
|
+ paymentForm.value.supplierId = detailData.value.id;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((paymentForm.value as any).id) {
|
|
|
+ // 更新
|
|
|
+ await updateBank(paymentForm.value);
|
|
|
+ ElMessage({ message: '更新成功', type: 'info' });
|
|
|
+ } else {
|
|
|
+ // 新增
|
|
|
+ await addBank(paymentForm.value);
|
|
|
+ ElMessage({ message: '新增成功', type: 'info' });
|
|
|
+ }
|
|
|
+
|
|
|
+ paymentDialogVisible.value = false;
|
|
|
+ // 刷新付款信息列表
|
|
|
+ await getPaymentInfo();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存付款信息失败:', e);
|
|
|
+ ElMessage.error('保存付款信息失败');
|
|
|
+ } finally {
|
|
|
+ paymentSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 获取地址列表 */
|
|
|
+const getAddressList = async () => {
|
|
|
+ let id = route.query.id as string;
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+ if (!id) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await listAddress({
|
|
|
+ supplierId: id,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+ addressList.value = res.data || res.rows || [];
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取地址列表失败:', e);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增地址 */
|
|
|
+const handleAddAddress = () => {
|
|
|
+ // 重置表单
|
|
|
+ addressForm.value = {
|
|
|
+ supplierNo: detailData.value.supplierNo,
|
|
|
+ supplierId: detailData.value.id,
|
|
|
+ shipperName: '',
|
|
|
+ shipperPhone: '',
|
|
|
+ shippingPostCode: '',
|
|
|
+ shippingProvincial: '',
|
|
|
+ shippingCity: '',
|
|
|
+ shippingCounty: '',
|
|
|
+ shippingAddress: '',
|
|
|
+ isSelf: 0
|
|
|
+ };
|
|
|
+ selectedAddressRegion.value = [];
|
|
|
+ addressDialogTitle.value = '添加地址';
|
|
|
+ addressDialogReadonly.value = false;
|
|
|
+ addressDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 查看地址 */
|
|
|
+const handleViewAddress = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getAddress(row.id);
|
|
|
+ Object.assign(addressForm.value, res.data);
|
|
|
+
|
|
|
+ // 回显省市区选择器
|
|
|
+ if (res.data.shippingProvincial && res.data.shippingCity && res.data.shippingCounty) {
|
|
|
+ const province = res.data.shippingProvincial;
|
|
|
+ const city = res.data.shippingCity;
|
|
|
+ const county = res.data.shippingCounty;
|
|
|
+
|
|
|
+ // 根据省市区名称查找对应的代码
|
|
|
+ const provinceItem = regionOptions.value.find((p: any) => p.label === province);
|
|
|
+ if (provinceItem) {
|
|
|
+ const cityItem = provinceItem.children?.find((c: any) => c.label === city);
|
|
|
+ if (cityItem) {
|
|
|
+ const districtItem = cityItem.children?.find((d: any) => d.label === county);
|
|
|
+ if (districtItem) {
|
|
|
+ selectedAddressRegion.value = [provinceItem.value, cityItem.value, districtItem.value];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ addressDialogTitle.value = '查看地址';
|
|
|
+ addressDialogReadonly.value = true;
|
|
|
+ addressDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取地址详情失败:', e);
|
|
|
+ ElMessage.error('获取地址详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 编辑地址 */
|
|
|
+const handleEditAddress = async (row: any) => {
|
|
|
+ try {
|
|
|
+ const res = await getAddress(row.id);
|
|
|
+ Object.assign(addressForm.value, res.data);
|
|
|
+
|
|
|
+ // 回显省市区选择器
|
|
|
+ if (res.data.shippingProvincial && res.data.shippingCity && res.data.shippingCounty) {
|
|
|
+ const province = res.data.shippingProvincial;
|
|
|
+ const city = res.data.shippingCity;
|
|
|
+ const county = res.data.shippingCounty;
|
|
|
+
|
|
|
+ // 根据省市区名称查找对应的代码
|
|
|
+ const provinceItem = regionOptions.value.find((p: any) => p.label === province);
|
|
|
+ if (provinceItem) {
|
|
|
+ const cityItem = provinceItem.children?.find((c: any) => c.label === city);
|
|
|
+ if (cityItem) {
|
|
|
+ const districtItem = cityItem.children?.find((d: any) => d.label === county);
|
|
|
+ if (districtItem) {
|
|
|
+ selectedAddressRegion.value = [provinceItem.value, cityItem.value, districtItem.value];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ addressDialogTitle.value = '编辑地址';
|
|
|
+ addressDialogReadonly.value = false;
|
|
|
+ addressDialogVisible.value = true;
|
|
|
+ } catch (e) {
|
|
|
+ console.error('获取地址详情失败:', e);
|
|
|
+ ElMessage.error('获取地址详情失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除地址 */
|
|
|
+const handleDeleteAddress = async (row: any) => {
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm('确认删除该地址吗?', '提示', {
|
|
|
+ confirmButtonText: '确认',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ });
|
|
|
+
|
|
|
+ await delAddress(row.id);
|
|
|
+ ElMessage({ message: '删除成功', type: 'info' });
|
|
|
+
|
|
|
+ // 刷新地址列表
|
|
|
+ getAddressList();
|
|
|
+ } catch (e: any) {
|
|
|
+ if (e !== 'cancel') {
|
|
|
+ console.error('删除地址失败:', e);
|
|
|
+ ElMessage.error('删除地址失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 地址省市区改变事件 */
|
|
|
+const handleAddressRegionChange = (value: string[]) => {
|
|
|
+ if (value && value.length === 3) {
|
|
|
+ // value 是 [省代码, 市代码, 区代码]
|
|
|
+ const [provinceCode, cityCode, districtCode] = value;
|
|
|
+
|
|
|
+ // 从 regionOptions 中查找对应的名称
|
|
|
+ let provinceName = '';
|
|
|
+ let cityName = '';
|
|
|
+ let districtName = '';
|
|
|
+
|
|
|
+ const province = regionOptions.value.find((p: any) => p.value === provinceCode);
|
|
|
+ if (province) {
|
|
|
+ provinceName = province.label;
|
|
|
+
|
|
|
+ const city = province.children?.find((c: any) => c.value === cityCode);
|
|
|
+ if (city) {
|
|
|
+ cityName = city.label;
|
|
|
+
|
|
|
+ const district = city.children?.find((d: any) => d.value === districtCode);
|
|
|
+ if (district) {
|
|
|
+ districtName = district.label;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新 addressForm
|
|
|
+ addressForm.value.shippingProvincial = provinceName;
|
|
|
+ addressForm.value.shippingCity = cityName;
|
|
|
+ addressForm.value.shippingCounty = districtName;
|
|
|
+ } else {
|
|
|
+ // 清空
|
|
|
+ addressForm.value.shippingProvincial = '';
|
|
|
+ addressForm.value.shippingCity = '';
|
|
|
+ addressForm.value.shippingCounty = '';
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交地址 */
|
|
|
+const handleAddressSubmit = async () => {
|
|
|
+ if (!addressFormRef.value) return;
|
|
|
+
|
|
|
+ addressFormRef.value.validate(async (valid: boolean) => {
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ addressSubmitLoading.value = true;
|
|
|
+
|
|
|
+ // 设置供应商编号和ID
|
|
|
+ if (!addressForm.value.supplierNo && detailData.value.supplierNo) {
|
|
|
+ addressForm.value.supplierNo = detailData.value.supplierNo;
|
|
|
+ }
|
|
|
+ if (!addressForm.value.supplierId && detailData.value.id) {
|
|
|
+ addressForm.value.supplierId = detailData.value.id;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((addressForm.value as any).id) {
|
|
|
+ // 更新
|
|
|
+ await updateAddress(addressForm.value);
|
|
|
+ ElMessage({ message: '更新成功', type: 'info' });
|
|
|
+ } else {
|
|
|
+ // 新增
|
|
|
+ await addAddress(addressForm.value);
|
|
|
+ ElMessage({ message: '新增成功', type: 'info' });
|
|
|
+ }
|
|
|
+
|
|
|
+ addressDialogVisible.value = false;
|
|
|
+ // 刷新地址列表
|
|
|
+ await getAddressList();
|
|
|
+ } catch (e) {
|
|
|
+ console.error('保存地址失败:', e);
|
|
|
+ ElMessage.error('保存地址失败');
|
|
|
+ } finally {
|
|
|
+ addressSubmitLoading.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ // 先初始化省市区数据
|
|
|
+ initRegionOptions();
|
|
|
+ // 初始化供货区域选项数据
|
|
|
+ initSupplyAreaOptions();
|
|
|
+
|
|
|
+ // 并行加载所有下拉框选项数据
|
|
|
+ await Promise.all([
|
|
|
+ getStaffOptions(),
|
|
|
+ getCompanyOptions(), // 获取公司下拉选项
|
|
|
+ getEnterpriseScaleOptions(), // 获取企业规模下拉选项
|
|
|
+ getIndustryCategoryOptions(), // 获取行业类别下拉选项
|
|
|
+ getSupplierLevelOptions(), // 获取供应商等级下拉选项
|
|
|
+ getSupplierTypeOptions(), // 获取供应商类型下拉选项
|
|
|
+ getContractTypeDict(), // 获取合同类型字典
|
|
|
+ getTaxRateData(), // 获取税率列表
|
|
|
+ getSettlementMethodData(), // 获取结算方式列表
|
|
|
+ getInvoiceTypeData(), // 获取发票类型列表
|
|
|
+ getAllBrandList(), // 获取所有品牌列表
|
|
|
+ getSystemBankData() // 获取银行列表
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 下拉框选项加载完成后,再获取详情数据
|
|
|
+ // getDetail 会自动从 userStore 获取 supplierId(如果 URL 中没有 id)
|
|
|
+ await getDetail();
|
|
|
+
|
|
|
+ // 只有在编辑模式或基础信息已保存时才加载其他数据
|
|
|
+ let id = route.query.id as string;
|
|
|
+ const mode = route.query.mode as string;
|
|
|
+
|
|
|
+ // 如果 URL 中没有 id,使用 userStore.supplierId
|
|
|
+ if (!id && userStore.supplierId) {
|
|
|
+ id = String(userStore.supplierId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (id && mode !== 'add') {
|
|
|
+ getContactList();
|
|
|
+ getProductCategories(); // 这个方法内部会调用 getSupplierSelectedCategories
|
|
|
+ getContractList(); // 获取合同列表
|
|
|
+ getPaymentInfo(); // 获取付款信息
|
|
|
+ getAuthorizationList(); // 获取授权详情列表
|
|
|
+ getAddressList(); // 获取地址列表
|
|
|
+ getSupplyAreaList(); // 获取供货区域列表
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.app-container {
|
|
|
+ background: #f0f2f5;
|
|
|
+ min-height: 100vh;
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-header {
|
|
|
+ background: #fff;
|
|
|
+ padding: 16px 24px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.back-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-right: 12px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.back-icon:hover {
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.header-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs {
|
|
|
+ background: #fff;
|
|
|
+ margin: 0;
|
|
|
+ padding: 0 24px;
|
|
|
+ margin-top: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs :deep(.el-tabs__header) {
|
|
|
+ margin: 0;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs :deep(.el-tabs__nav-wrap) {
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs :deep(.el-tabs__item) {
|
|
|
+ height: 48px;
|
|
|
+ line-height: 48px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs :deep(.el-tabs__item.is-active) {
|
|
|
+ color: #409eff;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-content {
|
|
|
+ padding: 24px;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.info-section {
|
|
|
+ margin-bottom: 40px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #333;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ padding-bottom: 12px;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title-row {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ padding-bottom: 12px;
|
|
|
+ border-bottom: 1px solid #e8e8e8;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title-text {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title-divider {
|
|
|
+ margin: 0 8px;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.supplier-no {
|
|
|
+ color: #409eff;
|
|
|
+ font-weight: normal;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-form :deep(.el-form-item) {
|
|
|
+ margin-bottom: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-form :deep(.el-form-item__label) {
|
|
|
+ color: #666;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-form :deep(.el-form-item__label::before) {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.form-row {
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.form-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ line-height: 32px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.form-item .label {
|
|
|
+ color: #666;
|
|
|
+ min-width: 100px;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.form-item .value {
|
|
|
+ color: #333;
|
|
|
+ flex: 1;
|
|
|
+ word-break: break-all;
|
|
|
+}
|
|
|
+
|
|
|
+.category-group {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 16px;
|
|
|
+}
|
|
|
+
|
|
|
+.category-group .el-checkbox {
|
|
|
+ margin-right: 0;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.supply-brand {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ padding: 8px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-input-wrapper {
|
|
|
+ margin-top: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-display-wrapper {
|
|
|
+ margin-top: 12px;
|
|
|
+ min-height: 40px;
|
|
|
+ padding: 8px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-tags-container {
|
|
|
+ min-height: 80px;
|
|
|
+ padding: 16px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-search-results {
|
|
|
+ max-height: 300px;
|
|
|
+ overflow-y: auto;
|
|
|
+ margin-bottom: 20px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.search-results-title {
|
|
|
+ padding: 10px 16px;
|
|
|
+ background: #f5f7fa;
|
|
|
+ font-weight: 500;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ border-bottom: 1px solid #e4e7ed;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-result-item {
|
|
|
+ padding: 12px 16px;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ border-bottom: 1px solid #f0f0f0;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-result-item:hover {
|
|
|
+ background-color: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-result-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-result-name {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #303133;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.brand-result-no {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-brands-section {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-label {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+}
|
|
|
+
|
|
|
+.image-upload {
|
|
|
+ display: inline-block;
|
|
|
+ margin-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-placeholder {
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #999;
|
|
|
+ font-size: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-placeholder:hover {
|
|
|
+ border-color: #409eff;
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+</style>
|