ShipmentDetailModal.vue 12.2 KB
<template>
  <j-modal
    :title="title"
    :width="width"
    :visible="visible"
    :confirmLoading="confirmLoading"
    switchFullscreen
    @ok="handleOk"
    @cancel="handleCancel"
    cancelText="关闭">
    <a-spin :spinning="confirmLoading">
      <a-form-model ref="form" :model="model" :rules="validatorRules">
        <a-row>
          <!-- 物料选择框:选择后先查库存,再加载批次 -->
          <a-form-model-item label="物料3" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="materialCode">
            <j-search-select-tag
              placeholder="请选择物料编码"
              v-model="model.materialCode"
              dict="material,name,code"
              @change="handleMaterialChange"
            :pageSize="10"
            :async="true">
            </j-search-select-tag>
          </a-form-model-item>

          <a-col :span="24">
            <a-form-model-item label="数量" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="qty">
              <a-input-number v-model="model.qty" placeholder="请输入数量" style="width: 100%"/>
            </a-form-model-item>
          </a-col>

          <a-col :span="24">
            <a-form-model-item label="重量" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="auxQty">
              <a-input-number v-model="model.auxQty" placeholder="请输入重量" style="width: 100%"/>
            </a-form-model-item>
          </a-col>

          <!-- 批次下拉框:带搜索+分页加载 -->
          <a-col :span="24">
            <a-form-model-item label="批次" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="batch">
              <a-select
                show-search
                placeholder="请选择批次"
                option-filter-prop="children"
                v-model="model.batch"
                :loading="batchLoading"
                :not-found-content="batchLoading ? '加载中...' : ''"
                @search="handleBatchSearch"
                @popupScroll="handleBatchScroll"
                @change="handleBatchChange"
              >
              <a-select-option v-for="item in batchOptions" :key="item.batch" :value="item.batch">
                {{ item.batch }}
              </a-select-option>
              <a-spin v-if="loadingMore" size="small" style="display: block; margin: 10px auto;" />
              </a-select>
            </a-form-model-item>
          </a-col>

          <a-col :span="24">
            <a-form-model-item label="长度" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="length">
              <a-input v-model="model.length" placeholder="请输入长度"></a-input>
            </a-form-model-item>
          </a-col>

          <a-col :span="24">
            <a-form-model-item label="宽度" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="width">
              <a-input v-model="model.width" placeholder="请输入宽度"></a-input>
            </a-form-model-item>
          </a-col>

          <!-- 库存状态选择框:切换后先查库存,再加载批次 -->
          <a-col :span="24">
            <a-form-model-item label="库存状态" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="inventoryStatus">
              <j-dict-select-tag
                type="list"
                v-model="model.inventoryStatus"
                dictCode="inventory_status"
                @change="handleInventoryStatusChange"
              placeholder="请选择库存状态"/>
            </a-form-model-item>
          </a-col>

          <a-col :span="24">
            <a-form-model-item label="库存数量" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="inventoryQty">
              <a-input-number v-model="model.inventoryQty" :disabled="true" style="width: 100%"/>
            </a-form-model-item>
          </a-col>
        </a-row>
      </a-form-model>
    </a-spin>
  </j-modal>
</template>

<script>
import { httpAction } from '@/api/manage'
import { validateDuplicateValue } from '@/utils/util'
import { getInventoryByShipmentDetail, getMaterialList, searchMaterialByCode, searchMaterialByCodeAndBatch } from '@/api/api'

export default {
  name: 'ShipmentDetailModal',
  components: {},
  props: {
    mainId: {
      type: String,
      required: false,
      default: ''
    }
  },
  data() {
    return {
      title: '操作',
      width: 800,
      visible: false,
      materialList: [],
      shipmentDetail: {},
      querySource: {},
      model: {},
      labelCol: {
        xs: { span: 24 },
        sm: { span: 5 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
      confirmLoading: false,
      validatorRules: {
        materialCode: [{ required: true, message: '请输入物料编码!' }],
        inventoryStatus: [{ required: true, message: '请输入库存状态!' }],
      },
      url: {
        add: '/shipment/shipmentHeader/addShipmentDetail',
        edit: '/shipment/shipmentHeader/editShipmentDetail',
      },
      // 批次下拉框相关变量
      batchOptions: [],
      batchLoading: false,
      loadingMore: false,
      batchSearchKey: '',
      batchPage: 1,
      batchPageSize: 20,
      hasMoreBatch: true
    }
  },
  created() {
    this.modelDefault = JSON.parse(JSON.stringify(this.model))
  },
  methods: {
    add() {
      let record = { inventoryStatus: 'good' }
      this.edit(record)
    },
    edit(record) {
      this.model = Object.assign({}, record)
      this.visible = true
      // 编辑时:若有物料编码+库存状态,先查库存再加载批次
      if (this.model.materialCode && this.model.inventoryStatus) {
        this.$nextTick(() => {
          this.getInventoryByShipmentDetail().then(() => {
            this.queryMaterialBatch()
          })
        })
      }
    },
    close() {
      this.$emit('close')
      this.visible = false
      this.$refs.form.clearValidate()
      this.resetBatchSelector()
    },

    // ---------------------- 核心修复:统一管控执行顺序 ----------------------
    /**
     * 物料编码变更:先查库存,再加载批次
     */
    handleMaterialChange() {
      // 清空批次和库存数量(避免旧数据残留)
      this.model.batch = ''
      this.model.inventoryQty = 0
      // 先查库存,库存查询成功后再加载批次
      this.getInventoryByShipmentDetail().then(() => {
        this.queryMaterialBatch()
      })
    },

    /**
     * 库存状态变更:先查库存,再加载批次
     */
    handleInventoryStatusChange() {
      // 清空批次和库存数量
      this.model.batch = ''
      this.model.inventoryQty = 0
      // 物料编码为空时不执行(避免无效请求)
      if (!this.model.materialCode) return
      // 先查库存,库存查询成功后再加载批次
      this.getInventoryByShipmentDetail().then(() => {
        this.queryMaterialBatch()
      })
    },

    /**
     * 批次变更:查询当前批次对应的库存数量
     */
    handleBatchChange() {
      // 批次为空时清空库存数量
      if (!this.model.batch) {
        this.model.inventoryQty = 0
        return
      }
      // 查当前批次的库存数量
      this.getInventoryByShipmentDetail()
    },

    // ---------------------- 修复库存查询:改为Promise返回,支持后续回调 ----------------------
    getInventoryByShipmentDetail() {
      // 返回Promise,让调用者能控制后续逻辑(如加载批次)
      return new Promise((resolve, reject) => {
        this.model['shipmentId'] = this.mainId
        // 必传参数校验(避免无效接口调用)
        if (!this.model.materialCode || !this.model.inventoryStatus) {
          this.model.inventoryQty = 0
          resolve()
          return
        }

        getInventoryByShipmentDetail(this.model).then((res) => {
          if (res.success) {
            // 只更新需要的字段(避免覆盖物料编码、库存状态等)
            this.model.inventoryQty = res.result.inventoryQty || 0
            // 若返回重量,同步更新重量字段(根据实际业务调整)
            if (res.result.auxQty) {
              this.model.auxQty = res.result.auxQty
            }
          } else {
            this.model.inventoryQty = 0
            this.$message.warning(res.message || '获取库存数量失败')
          }
          resolve() // 库存查询完成,通知后续逻辑(如加载批次)
        }).catch((err) => {
          this.model.inventoryQty = 0
          this.$message.error('库存查询接口异常')
          reject(err)
        })
      })
    },

    // ---------------------- 批次下拉框逻辑(保留,新增库存状态参数) ----------------------
    resetBatchSelector() {
      this.batchOptions = []
      this.batchPage = 1
      this.hasMoreBatch = true
      this.batchSearchKey = ''
    },

    handleBatchSearch(keyword) {
      this.batchSearchKey = keyword
      this.batchPage = 1
      this.batchOptions = []
      this.hasMoreBatch = true
      this.loadBatchData()
    },

    handleBatchScroll(e) {
      const target = e.target
      if (target.scrollHeight - target.scrollTop <= target.clientHeight + 100 &&
        !this.batchLoading &&
        !this.loadingMore &&
        this.hasMoreBatch) {
        this.loadMoreBatch()
      }
    },

    loadBatchData() {
      // 必传参数校验(物料编码+库存状态)
      if (!this.model.materialCode || !this.model.inventoryStatus) {
        this.batchOptions = []
        this.batchLoading = false
        return
      }

      this.batchLoading = true
      // 请求参数:新增inventoryStatus(库存状态),后端需支持该参数筛选
      const params = {
        materialCode: this.model.materialCode,
        inventoryStatus: this.model.inventoryStatus,
        batchKeyword: this.batchSearchKey,
        page: this.batchPage,
        pageSize: this.batchPageSize
      }

      this.searchBatchByMaterial(params).then(res => {
        if (res.success) {
          const newOptions = res.result.list || []
          this.batchOptions = this.batchPage === 1 ? newOptions : [...this.batchOptions, ...newOptions]
          this.hasMoreBatch = newOptions.length === this.batchPageSize
        } else {
          this.batchOptions = []
          this.$message.warning(res.message || '获取批次列表失败')
        }
      }).finally(() => {
        this.batchLoading = false
        this.loadingMore = false
      })
    },

    loadMoreBatch() {
      if (!this.hasMoreBatch) return
      this.loadingMore = true
      this.batchPage++
      this.loadBatchData()
    },

    queryMaterialBatch() {
      this.resetBatchSelector()
      this.$nextTick(() => {
        this.loadBatchData()
      })
    },

    searchBatchByMaterial(params) {
      if (!params.materialCode || !params.inventoryStatus) {
        return Promise.resolve({ success: true, result: { list: [] } })
      }

      return searchMaterialByCodeAndBatch(params);
    },

    // ---------------------- 原有提交逻辑(保持不变) ----------------------
    handleOk() {
      const that = this
      this.$refs.form.validate(valid => {
        if (valid) {
          that.confirmLoading = true
          let httpurl = ''
          let method = ''
          if (!this.model.id) {
            httpurl += this.url.add
            method = 'post'
          } else {
            httpurl += this.url.edit
            method = 'put'
          }
          this.model['shipmentId'] = this.mainId
          if (this.model['qty'] === '' || this.model['qty'] === undefined) {
            this.model['qty'] = 1
          }
          httpAction(httpurl, this.model, method).then((res) => {
            if (res.success) {
              that.$message.success(res.message)
              that.$emit('ok')
              that.$emit('dataSearch')
            } else {
              that.$message.warning(res.message)
            }
          }).finally(() => {
            that.confirmLoading = false
            that.close()
          })
        } else {
          return false
        }
      })
    },

    handleCancel() {
      this.close()
    },

    // 原有物料搜索逻辑(若未使用可保留或删除)
    searchMaterial() {
      const that = this
      that.querySource.code = that.model.materialCode
      getMaterialList(that.querySource).then((res) => {
        that.materialList = res.result
      })
    }
  }
}
</script>