编辑 | blame | 历史 | 原始文档

采购台账-总合同号联动选择及附件查看

涉及页面

  • 供应商管理详情页(新增合同记录Tab)
  • 采购台账列表页/新增编辑页

新增API

方法 路径 说明
GET /basic/supplier-contract/list/{supplierId} 查询供应商合同记录列表(供下拉选择)
GET /basic/supplier-contract/{id} 获取供应商合同记录详情
POST /basic/supplier-contract 新增供应商合同记录
PUT /basic/supplier-contract 修改供应商合同记录
DELETE /basic/supplier-contract/{id} 删除供应商合同记录
GET /basic/supplier-contract/files/byContractNo?masterContractNo=xxx 根据总合同号查询附件

前端修改点

1. 供应商管理详情页 - 添加合同记录Tab

<el-tabs v-model="activeTab">
  <!-- 基本信息Tab -->
  <el-tab-pane label="基本信息" name="basic">...</el-tab-pane>
  <!-- 合同记录Tab -->
  <el-tab-pane label="合同记录" name="contract">
    <el-button type="primary" size="small" @click="handleAddContract">新增合同记录</el-button>
    <el-table :data="contractList" style="width: 100%; margin-top: 15px">
      <el-table-column prop="masterContractNo" label="总合同号" />
      <el-table-column prop="entryDate" label="录入日期" width="180" />
      <el-table-column prop="entryPerson" label="录入人" width="120" />
      <el-table-column prop="remark" label="备注" show-overflow-tooltip />
      <el-table-column label="附件" width="100">
        <template #default="{ row }">
          <el-link type="primary" v-if="row.fileList && row.fileList.length" @click="handleViewFiles(row)">
            查看({{ row.fileList.length }})
          </el-link>
          <span v-else>-</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" width="150">
        <template #default="{ row }">
          <el-button type="text" size="small" @click="handleEditContract(row)">编辑</el-button>
          <el-button type="text" size="small" style="color: #f56c6c" @click="handleDeleteContract(row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-tab-pane>
</el-tabs>

2. 新增/编辑合同记录弹窗

<el-dialog :title="contractDialogTitle" v-model="contractDialogVisible" width="600px">
  <el-form :model="contractForm" :rules="contractRules" ref="contractFormRef" label-width="100px">
    <el-form-item label="总合同号" prop="masterContractNo">
      <el-input v-model="contractForm.masterContractNo" placeholder="请输入总合同号" />
    </el-form-item>
    <el-form-item label="录入日期" prop="entryDate">
      <el-date-picker
        v-model="contractForm.entryDate"
        type="datetime"
        placeholder="选择日期时间"
        value-format="yyyy-MM-dd HH:mm:ss"
        style="width: 100%"
      />
    </el-form-item>
    <el-form-item label="录入人" prop="entryPerson">
      <el-input v-model="contractForm.entryPerson" placeholder="请输入录入人" />
    </el-form-item>
    <el-form-item label="附件">
      <file-upload
        v-model="contractForm.storageBlobDTOs"
        :record-type="'supplier_contract_record'"
        :record-id="contractForm.id"
      />
    </el-form-item>
    <el-form-item label="备注">
      <el-input v-model="contractForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
    </el-form-item>
  </el-form>
  <template #footer>
    <el-button @click="contractDialogVisible = false">取消</el-button>
    <el-button type="primary" @click="submitContractForm">确定</el-button>
  </template>
</el-dialog>

3. 采购台账新增/编辑页 - 供应商选择后联动总合同号

<el-form-item label="供应商" prop="supplierId">
  <el-select
    v-model="form.supplierId"
    placeholder="请选择供应商"
    filterable
    @change="handleSupplierChange"
  >
    <el-option
      v-for="item in supplierList"
      :key="item.id"
      :label="item.supplierName"
      :value="item.id"
    />
  </el-select>
</el-form-item>

<el-form-item label="总合同号" prop="masterContractNo">
  <el-select
    v-model="form.masterContractNo"
    placeholder="请先选择供应商"
    filterable
    clearable
    :disabled="!form.supplierId"
  >
    <el-option
      v-for="item in contractList"
      :key="item.id"
      :label="item.masterContractNo"
      :value="item.masterContractNo"
    />
  </el-select>
</el-form-item>

4. 采购台账列表页 - 操作栏添加查看总合同附件按钮

<el-table-column label="操作" width="200">
  <template #default="{ row }">
    <el-button type="text" size="small" @click="handleEdit(row)">编辑</el-button>
    <el-button type="text" size="small" @click="handleDelete(row)">删除</el-button>
    <el-button
      type="text"
      size="small"
      v-if="row.masterContractNo"
      @click="handleViewContractFiles(row)"
    >查看附件</el-button>
  </template>
</el-table-column>

5. 总合同附件查看弹窗

<el-dialog title="总合同附件" v-model="contractFileDialogVisible" width="600px">
  <el-table :data="contractFileList" v-if="contractFileList.length">
    <el-table-column prop="name" label="文件名称" />
    <el-table-column prop="byteSize" label="文件大小" width="120">
      <template #default="{ row }">
        {{ formatFileSize(row.byteSize) }}
      </template>
    </el-table-column>
    <el-table-column label="操作" width="150">
      <template #default="{ row }">
        <el-link type="primary" :href="row.previewURL" target="_blank">预览</el-link>
        <el-link type="primary" :href="row.downloadURL" style="margin-left: 10px">下载</el-link>
      </template>
    </el-table-column>
  </el-table>
  <el-empty v-else description="暂无附件" />
</el-dialog>

6. data 数据

data() {
  return {
    // 合同列表(供下拉选择)
    contractList: [],
    // 合同记录列表(供应商详情页)
    contractRecordList: [],
    contractDialogVisible: false,
    contractDialogTitle: '',
    contractForm: {
      id: null,
      supplierId: null,
      masterContractNo: '',
      entryDate: '',
      entryPerson: '',
      entryPersonId: null,
      remark: '',
      storageBlobDTOs: []
    },
    contractRules: {
      masterContractNo: [{ required: true, message: '请输入总合同号', trigger: 'blur' }],
      entryDate: [{ required: true, message: '请选择录入日期', trigger: 'change' }]
    },
    // 总合同附件弹窗
    contractFileDialogVisible: false,
    contractFileList: []
  }
}

7. 方法

methods: {
  // 供应商选择变化时,加载该供应商的合同列表
  async handleSupplierChange(supplierId) {
    this.form.masterContractNo = ''  // 清空总合同号
    this.contractList = []
    if (!supplierId) return
    
    const res = await this.$http.get(`/basic/supplier-contract/list/${supplierId}`)
    if (res.code === 200) {
      this.contractList = res.data
    }
  },

  // 获取供应商合同记录列表(供应商详情页)
  async getContractList(supplierId) {
    const res = await this.$http.get(`/basic/supplier-contract/list/${supplierId}`)
    if (res.code === 200) {
      this.contractRecordList = res.data
    }
  },

  // 新增合同记录
  handleAddContract() {
    this.contractDialogTitle = '新增合同记录'
    this.contractForm = {
      id: null,
      supplierId: this.supplierId,
      masterContractNo: '',
      entryDate: '',
      entryPerson: '',
      entryPersonId: null,
      remark: '',
      storageBlobDTOs: []
    }
    this.contractDialogVisible = true
  },

  // 编辑合同记录
  async handleEditContract(row) {
    this.contractDialogTitle = '编辑合同记录'
    const res = await this.$http.get(`/basic/supplier-contract/${row.id}`)
    if (res.code === 200) {
      this.contractForm = {
        ...res.data,
        storageBlobDTOs: res.data.fileList ? res.data.fileList.map(f => ({ id: f.id })) : []
      }
      this.contractDialogVisible = true
    }
  },

  // 删除合同记录
  async handleDeleteContract(row) {
    await this.$confirm('确定删除该合同记录吗?', '提示', { type: 'warning' })
    const res = await this.$http.delete(`/basic/supplier-contract/${row.id}`)
    if (res.code === 200) {
      this.$message.success('删除成功')
      this.getContractList(this.supplierId)
    }
  },

  // 提交合同记录表单
  async submitContractForm() {
    await this.$refs.contractFormRef.validate()
    const res = await this.$http.post('/basic/supplier-contract', this.contractForm)
    if (res.code === 200) {
      this.$message.success('操作成功')
      this.contractDialogVisible = false
      this.getContractList(this.supplierId)
    }
  },

  // 查看总合同附件
  async handleViewContractFiles(row) {
    if (!row.masterContractNo) {
      this.$message.warning('该记录没有总合同号')
      return
    }
    const res = await this.$http.get('/basic/supplier-contract/files/byContractNo', {
      params: { masterContractNo: row.masterContractNo }
    })
    if (res.code === 200) {
      this.contractFileList = res.data || []
      this.contractFileDialogVisible = true
    }
  },

  // 格式化文件大小
  formatFileSize(bytes) {
    if (!bytes) return '0 B'
    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
  },

  // 查看附件列表
  handleViewFiles(row) {
    this.contractFileList = row.fileList || []
    this.contractFileDialogVisible = true
  },

  // 编辑页打开时回显总合同号
  async handleEdit(row) {
    this.form = { ...row }
    this.dialogVisible = true
    
    // 加载供应商的合同列表
    if (row.supplierId) {
      const res = await this.$http.get(`/basic/supplier-contract/list/${row.supplierId}`)
      if (res.code === 200) {
        this.contractList = res.data
      }
    }
  }
}

8. 采购台账列表页 - 表格显示总合同号列

<el-table-column prop="masterContractNo" label="总合同号" width="150" show-overflow-tooltip />

后端文件清单

文件路径 说明
src/main/java/com/ruoyi/basic/pojo/SupplierContractRecord.java 实体类
src/main/java/com/ruoyi/basic/dto/SupplierContractRecordDto.java DTO
src/main/java/com/ruoyi/basic/mapper/SupplierContractRecordMapper.java Mapper接口
src/main/resources/mapper/basic/SupplierContractRecordMapper.xml Mapper XML
src/main/java/com/ruoyi/basic/service/SupplierContractRecordService.java Service接口
src/main/java/com/ruoyi/basic/service/impl/SupplierContractRecordServiceImpl.java Service实现
src/main/java/com/ruoyi/basic/controller/SupplierContractRecordController.java Controller
src/main/java/com/ruoyi/basic/enums/RecordTypeEnum.java 添加枚举值 SUPPLIER_CONTRACT_RECORD

注意事项

  • 总合同号来源于供应商管理的合同记录子表
  • 选择顺序:先选供应商 -> 自动加载该供应商的合同列表 -> 再选总合同号
  • 采购台账表已有 master_contract_no 字段,无需修改数据库
  • 查看附件按钮仅在总合同号存在时显示
  • 附件列表通过总合同号查询,支持预览和下载