gaoluyang
2026-05-13 d3840d5971aa6e1272f17acce28a5f96a8e3ab29
浪潮
1.添加仓库管理页面
2.入库、出库添加新增编辑功能并联调
已添加2个文件
已修改9个文件
1448 ■■■■■ 文件已修改
src/api/inventoryManagement/stockInventory.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockOut.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/warehouse.js 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/customerFile/index.vue 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/customerFileOpenSea/index.vue 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/dispatchLog/Record.vue 362 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/Record.vue 333 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Record.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/warehouseManagement/index.vue 491 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockInventory.js
@@ -95,3 +95,12 @@
    });
};
// æ›´æ–°åº“存记录
export const updateStockInventory = (params) => {
    return request({
        url: "/stockInventory/update",
        method: "post",
        data: params,
    });
};
src/api/inventoryManagement/stockOut.js
@@ -35,3 +35,12 @@
        data,
    });
}
// æ›´æ–°å‡ºåº“记录
export const updateStockOutRecord = (id, data) => {
    return request({
        url: `/stockOutRecord/${id}`,
        method: "put",
        data,
    });
}
src/api/inventoryManagement/warehouse.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
import request from "@/utils/request";
// èŽ·å–ä»“åº“åˆ—è¡¨ï¼ˆåˆ†é¡µï¼‰
export const getWarehousePage = (params) => {
  return request({
    url: "/warehouseInfo/listPage",
    method: "get",
    params,
  });
};
// èŽ·å–ä»“åº“åˆ—è¡¨ï¼ˆä¸åˆ†é¡µï¼‰
export const getWarehouseList = (params) => {
  return request({
    url: "/warehouseInfo/list",
    method: "get",
    params,
  });
};
// æ ¹æ®ID获取仓库详情
export const getWarehouseById = (id) => {
  return request({
    url: `/warehouseInfo/${id}`,
    method: "get",
  });
};
// æ–°å¢žä»“库
export const addWarehouse = (data) => {
  return request({
    url: "/warehouseInfo/add",
    method: "post",
    data,
  });
};
// æ›´æ–°ä»“库
export const updateWarehouse = (data) => {
  return request({
    url: "/warehouseInfo/edit",
    method: "post",
    data,
  });
};
// åˆ é™¤ä»“库
export const delWarehouse = (ids) => {
  return request({
    url: "/warehouseInfo/delete",
    method: "post",
    data: ids,
  });
};
// æ›´æ–°ä»“库状态
export const updateWarehouseStatus = (id, status) => {
  return request({
    url: `/warehouseInfo/${id}/status`,
    method: "put",
    params: { status },
  });
};
src/views/basicData/customerFile/index.vue
@@ -136,21 +136,23 @@
            </el-form-item>
          </el-col>
        </el-row>
        <!-- è”系人功能已迁移到联系人管理页面
        <!-- è”系人列表 -->
        <el-row :gutter="30"
                v-for="(contact, index) in formYYs.contactList"
                v-for="(contact, index) in form.contactList"
                :key="index">
          <el-col :span="12">
            <el-form-item label="联系人:"
                          prop="contactPerson">
            <el-form-item :label="index === 0 ? '联系人:' : ''"
                          :prop="'contactList.' + index + '.contactPerson'"
                          :rules="{ required: true, message: '请输入联系人', trigger: 'blur' }">
              <el-input v-model="contact.contactPerson"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话:"
                          prop="contactPhone">
            <el-form-item :label="index === 0 ? '联系电话:' : ''"
                          :prop="'contactList.' + index + '.contactPhone'"
                          :rules="{ required: true, message: '请输入联系电话', trigger: 'blur' }">
              <div style="display: flex; align-items: center;width: 100%;">
                <el-input v-model="contact.contactPhone"
                          placeholder="请输入"
@@ -158,7 +160,8 @@
                <el-button @click="removeContact(index)"
                           type="danger"
                           circle
                           style="margin-left: 5px;">
                           style="margin-left: 5px;"
                           :disabled="form.contactList.length <= 1">
                  <el-icon>
                    <Close />
                  </el-icon>
@@ -168,8 +171,9 @@
          </el-col>
        </el-row>
        <el-button @click="addNewContact"
                   style="margin-bottom: 10px;">+ æ–°å¢žè”系人</el-button>
        -->
                   style="margin-bottom: 10px;"
                   type="primary"
                   plain>+ æ–°å¢žè”系人</el-button>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="维护人:"
@@ -868,6 +872,12 @@
      companyPhone: "",
      contactPerson: "",
      contactPhone: "",
      contactList: [
        {
          contactPerson: "",
          contactPhone: "",
        },
      ],
      maintainer: "",
      maintenanceTime: "",
      basicBankAccount: "",
@@ -955,15 +965,15 @@
  });
  const { searchForm, form, rules } = toRefs(data);
  const addNewContact = () => {
    formYYs.value.contactList.push({
    form.value.contactList.push({
      contactPerson: "",
      contactPhone: "",
    });
  };
  const removeContact = index => {
    if (formYYs.value.contactList.length > 1) {
      formYYs.value.contactList.splice(index, 1);
    if (form.value.contactList.length > 1) {
      form.value.contactList.splice(index, 1);
    }
  };
  // æŸ¥è¯¢åˆ—表
@@ -1008,7 +1018,7 @@
    operationType.value = type;
    form.value = {};
    form.value.maintainer = userStore.nickName;
    formYYs.value.contactList = [
    form.value.contactList = [
      {
        contactPerson: "",
        contactPhone: "",
@@ -1022,14 +1032,19 @@
    if (type === "edit") {
      getCustomer(row.id).then(res => {
        form.value = { ...res.data };
        formYYs.value.contactList = res.data.contactPerson
        // ä¼˜å…ˆä½¿ç”¨åŽç«¯è¿”回的contactList数组,如果没有则使用逗号分隔的字符串转换
        if (res.data.contactList && res.data.contactList.length > 0) {
          form.value.contactList = res.data.contactList;
        } else if (res.data.contactPerson) {
          form.value.contactList = res.data.contactPerson
          .split(",")
          .map((item, index) => {
            return {
              contactPerson: item,
              contactPhone: res.data.contactPhone.split(",")[index],
                contactPhone: res.data.contactPhone ? res.data.contactPhone.split(",")[index] : "",
            };
          });
        }
      });
    }
    dialogFormVisible.value = true;
@@ -1048,13 +1063,13 @@
  };
  // æäº¤æ–°å¢ž
  const submitAdd = () => {
    if (formYYs.value.contactList.length < 1) {
    if (form.value.contactList.length < 1) {
      return proxy.$modal.msgWarning("请至少添加一个联系人");
    }
    form.value.contactPerson = formYYs.value.contactList
    form.value.contactPerson = form.value.contactList
      .map(item => item.contactPerson)
      .join(",");
    form.value.contactPhone = formYYs.value.contactList
    form.value.contactPhone = form.value.contactList
      .map(item => item.contactPhone)
      .join(",");
    addCustomer(form.value).then(res => {
@@ -1065,10 +1080,10 @@
  };
  // æäº¤ä¿®æ”¹
  const submitEdit = () => {
    form.value.contactPerson = formYYs.value.contactList
    form.value.contactPerson = form.value.contactList
      .map(item => item.contactPerson)
      .join(",");
    form.value.contactPhone = formYYs.value.contactList
    form.value.contactPhone = form.value.contactList
      .map(item => item.contactPhone)
      .join(",");
    updateCustomer(form.value).then(res => {
src/views/basicData/customerFileOpenSea/index.vue
@@ -133,21 +133,23 @@
            </el-form-item>
          </el-col>
        </el-row>
        <!-- è”系人功能已迁移到联系人管理页面
        <!-- è”系人列表 -->
        <el-row :gutter="30"
                v-for="(contact, index) in formYYs.contactList"
                v-for="(contact, index) in form.contactList"
                :key="index">
          <el-col :span="12">
            <el-form-item label="联系人:"
                          prop="contactPerson">
            <el-form-item :label="index === 0 ? '联系人:' : ''"
                          :prop="'contactList.' + index + '.contactPerson'"
                          :rules="{ required: true, message: '请输入联系人', trigger: 'blur' }">
              <el-input v-model="contact.contactPerson"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="联系电话:"
                          prop="contactPhone">
            <el-form-item :label="index === 0 ? '联系电话:' : ''"
                          :prop="'contactList.' + index + '.contactPhone'"
                          :rules="{ required: true, message: '请输入联系电话', trigger: 'blur' }">
              <div style="display: flex; align-items: center;width: 100%;">
                <el-input v-model="contact.contactPhone"
                          placeholder="请输入"
@@ -155,7 +157,8 @@
                <el-button @click="removeContact(index)"
                           type="danger"
                           circle
                           style="margin-left: 5px;">
                           style="margin-left: 5px;"
                           :disabled="form.contactList.length <= 1">
                  <el-icon>
                    <Close />
                  </el-icon>
@@ -165,8 +168,9 @@
          </el-col>
        </el-row>
        <el-button @click="addNewContact"
                   style="margin-bottom: 10px;">+ æ–°å¢žè”系人</el-button>
        -->
                   style="margin-bottom: 10px;"
                   type="primary"
                   plain>+ æ–°å¢žè”系人</el-button>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="维护人:"
@@ -987,6 +991,12 @@
      companyPhone: "",
      contactPerson: "",
      contactPhone: "",
      contactList: [
        {
          contactPerson: "",
          contactPhone: "",
        },
      ],
      maintainer: "",
      maintenanceTime: "",
      basicBankAccount: "",
@@ -1074,15 +1084,15 @@
  });
  const { searchForm, form, rules } = toRefs(data);
  const addNewContact = () => {
    formYYs.value.contactList.push({
    form.value.contactList.push({
      contactPerson: "",
      contactPhone: "",
    });
  };
  const removeContact = index => {
    if (formYYs.value.contactList.length > 1) {
      formYYs.value.contactList.splice(index, 1);
    if (form.value.contactList.length > 1) {
      form.value.contactList.splice(index, 1);
    }
  };
  // æŸ¥è¯¢åˆ—表
@@ -1128,7 +1138,7 @@
    operationType.value = type;
    form.value = {};
    form.value.maintainer = userStore.nickName;
    formYYs.value.contactList = [
    form.value.contactList = [
      {
        contactPerson: "",
        contactPhone: "",
@@ -1142,14 +1152,19 @@
    if (type === "edit") {
      getCustomer(row.id).then(res => {
        form.value = { ...res.data };
        formYYs.value.contactList = res.data.contactPerson
        // ä¼˜å…ˆä½¿ç”¨åŽç«¯è¿”回的contactList数组,如果没有则使用逗号分隔的字符串转换
        if (res.data.contactList && res.data.contactList.length > 0) {
          form.value.contactList = res.data.contactList;
        } else if (res.data.contactPerson) {
          form.value.contactList = res.data.contactPerson
          .split(",")
          .map((item, index) => {
            return {
              contactPerson: item,
              contactPhone: res.data.contactPhone.split(",")[index],
                contactPhone: res.data.contactPhone ? res.data.contactPhone.split(",")[index] : "",
            };
          });
        }
      });
    }
    dialogFormVisible.value = true;
@@ -1168,13 +1183,13 @@
  };
  // æäº¤æ–°å¢ž
  const submitAdd = () => {
    if (formYYs.value.contactList.length < 1) {
    if (form.value.contactList.length < 1) {
      return proxy.$modal.msgWarning("请至少添加一个联系人");
    }
    form.value.contactPerson = formYYs.value.contactList
    form.value.contactPerson = form.value.contactList
      .map(item => item.contactPerson)
      .join(",");
    form.value.contactPhone = formYYs.value.contactList
    form.value.contactPhone = form.value.contactList
      .map(item => item.contactPhone)
      .join(",");
    addCustomer(form.value).then(res => {
@@ -1185,10 +1200,10 @@
  };
  // æäº¤ä¿®æ”¹
  const submitEdit = () => {
    form.value.contactPerson = formYYs.value.contactList
    form.value.contactPerson = form.value.contactList
      .map(item => item.contactPerson)
      .join(",");
    form.value.contactPhone = formYYs.value.contactList
    form.value.contactPhone = form.value.contactList
      .map(item => item.contactPhone)
      .join(",");
    updateCustomer(form.value).then(res => {
src/views/inventoryManagement/dispatchLog/Record.vue
@@ -31,6 +31,7 @@
        >
      </div>
      <div>
        <el-button type="primary" @click="handleAdd">新增</el-button>
        <el-button type="primary" @click="handleBatchApprove">审批</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
@@ -94,6 +95,17 @@
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="120" align="center" fixed="right">
          <template #default="scope">
            <el-button
              v-if="scope.row.approvalStatus !== 1 && scope.row.approvalStatus !== '1' && scope.row.approvalStatus !== 'approved' && scope.row.approvalStatus !== 'APPROVED'"
              link
              type="primary"
              size="small"
              @click="handleEdit(scope.row)">编辑</el-button>
            <span v-else style="color: #999; font-size: 12px;">已通过</span>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
@@ -104,24 +116,160 @@
        @pagination="paginationChange"
      />
    </div>
    <!-- æ–°å¢ž/编辑对话框 -->
    <el-dialog v-model="dialogVisible"
               :title="dialogTitle"
               width="800"
               @close="closeDialog">
      <el-form ref="formRef"
               :model="formState"
               label-width="140px"
               label-position="top">
        <el-form-item label="产品名称"
                      prop="productModelId"
                      :rules="[
                        {
                          required: true,
                          message: '请选择产品',
                          trigger: 'change',
                        }
                      ]">
          <el-button type="primary"
                     @click="showProductSelect = true">
            {{ formState.productName ? formState.productName : '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item label="规格"
                      prop="productModelName">
          <el-input v-model="formState.productModelName" disabled />
        </el-form-item>
        <el-form-item label="单位"
                      prop="unit">
          <el-input v-model="formState.unit" disabled />
        </el-form-item>
        <el-form-item label="库存类型"
                      prop="type"
                      :rules="[
                        {
                          required: true,
                          message: '请选择库存类型',
                          trigger: 'change',
                        }
                      ]">
          <el-select v-model="formState.type"
                     placeholder="请选择库存类型"
                     :disabled="isEdit">
            <el-option label="合格库存"
                       value="qualified" />
            <el-option label="不合格库存"
                       value="unqualified" />
          </el-select>
        </el-form-item>
        <el-form-item label="出库数量"
                      prop="qualitity"
                      :rules="[
                        {
                          required: true,
                          message: '请输入出库数量',
                          trigger: 'blur',
                        },
                        {
                          validator: (rule, value, callback) => {
                            if (formState.maxStock > 0 && value > formState.maxStock) {
                              callback('出库数量不能超过当前批号库存 ' + formState.maxStock);
                            } else {
                              callback();
                            }
                          },
                          trigger: 'blur',
                        }
                      ]">
          <el-input-number v-model="formState.qualitity"
                           :step="1"
                           :min="1"
                           :max="formState.maxStock > 0 ? formState.maxStock : undefined"
                           style="width: 100%" />
        </el-form-item>
        <el-form-item label="批号"
                      prop="batchNo"
                      :rules="[
                        {
                          required: true,
                          message: '请选择批号',
                          trigger: 'change',
                        }
                      ]">
          <el-select v-model="formState.batchNo"
                     placeholder="请选择批号"
                     clearable
                     :disabled="isEdit"
                     @change="handleBatchNoChange"
                     style="width: 100%">
            <el-option v-for="batch in batchNoList"
                       :key="batch"
                       :label="batch + ' (库存: ' + (batchNoStockMap[batch] || 0) + ')'"
                       :value="batch" />
          </el-select>
        </el-form-item>
        <el-form-item v-if="formState.batchNo && batchNoStockMap[formState.batchNo]"
                      label="当前批号库存"
                      prop="currentStock">
          <el-input v-model="batchNoStockMap[formState.batchNo]" disabled />
        </el-form-item>
        <el-form-item v-if="isEdit"
                      label="来源"
                      prop="recordType">
          <el-select v-model="formState.recordType"
                     placeholder="请选择来源"
                     disabled>
            <el-option v-for="item in stockRecordTypeOptions"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="formState.remark"
                    type="textarea" />
        </el-form-item>
      </el-form>
      <!-- äº§å“é€‰æ‹©å¼¹çª— -->
      <ProductSelectDialog v-model="showProductSelect"
                           @confirm="handleProductSelect"
                           :top-product-parent-id="props.topParentProductId"
                           request-url="/basic/product/pageModelAndQua"
                           single />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
          <el-button @click="closeDialog">取消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref } from "vue";
import { ElMessageBox } from "element-plus";
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import { ref, reactive, toRefs, computed, getCurrentInstance, watch, onMounted } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";
import useUserStore from "@/store/modules/user";
import { getCurrentDate } from "@/utils/index.js";
import {
  getStockOutPage,
  delPendingStockOut,
  batchApproveStockOutRecords,
  updateStockOutRecord,
} from "@/api/inventoryManagement/stockOut.js";
import {
  findAllQualifiedStockOutRecordTypeOptions,
  findAllUnQualifiedStockOutRecordTypeOptions,
} from "@/api/basicData/enum.js";
import { addStockOutRecordOnly } from "@/api/inventoryManagement/stockInventory.js";
import { addUnqualifiedStockOutRecordOnly } from "@/api/inventoryManagement/stockUninventory.js";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
@@ -130,6 +278,10 @@
const tableLoading = ref(false);
// æ¥æºç±»åž‹é€‰é¡¹
const stockRecordTypeOptions = ref([]);
// æ‰¹å·åˆ—表(从batchNoMaps获取)
const batchNoList = ref([]);
// æ‰¹å·åº“存映射
const batchNoStockMap = ref({});
const page = reactive({
  current: 1,
  size: 100,
@@ -161,6 +313,40 @@
  },
});
const { searchForm } = toRefs(data);
// å¯¹è¯æ¡†ç›¸å…³
const dialogVisible = ref(false);
const dialogType = ref('add'); // 'add' æˆ– 'edit'
const dialogTitle = computed(() => dialogType.value === 'add' ? '新增出库记录' : '编辑出库记录');
const isEdit = computed(() => dialogType.value === 'edit');
const formRef = ref();
const showProductSelect = ref(false);
// è¡¨å•数据
const formState = ref({
  id: undefined,
  productId: undefined,
  productModelId: undefined,
  productName: "",
  productModelName: "",
  unit: "",
  type: undefined,
  qualitity: 0,
  batchNo: null,
  recordType: "",
  remark: "",
  maxStock: 0, // å½“前选中批号的最大库存
});
// æ‰¹å·ä¸ºç©ºæ—¶è½¬ä¸º null
watch(
  () => formState.value.batchNo,
  val => {
    if (val === "") {
      formState.value.batchNo = null;
    }
  }
);
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
@@ -239,6 +425,178 @@
  return "warning";
};
// æ–°å¢ž
const handleAdd = () => {
  dialogType.value = 'add';
  resetForm();
  // æ ¹æ®å½“前tab设置默认库存类型
  formState.value.type = props.type === '0' ? 'qualified' : 'unqualified';
  dialogVisible.value = true;
};
// ç¼–辑
const handleEdit = (row) => {
  dialogType.value = 'edit';
  resetForm();
  // å¡«å……表单数据
  formState.value = {
    id: row.id,
    productId: row.productId,
    productModelId: row.productModelId,
    productName: row.productName,
    productModelName: row.model,
    unit: row.unit,
    type: props.type === '0' ? 'qualified' : 'unqualified',
    qualitity: row.stockOutNum,
    batchNo: row.batchNo,
    recordType: row.recordType,
    remark: row.remark || "",
    maxStock: row.stockOutNum || 0, // ç¼–辑时使用当前出库数量作为最大库存(因为是修改已有记录)
  };
  // ç¼–辑时从batchNoMaps获取批号列表
  if (row.batchNoMaps && Object.keys(row.batchNoMaps).length > 0) {
    batchNoList.value = Object.keys(row.batchNoMaps);
    batchNoStockMap.value = row.batchNoMaps;
  } else if (row.batchNo) {
    batchNoList.value = [row.batchNo];
    batchNoStockMap.value = { [row.batchNo]: row.stockOutNum || 0 };
  } else {
    batchNoList.value = [];
    batchNoStockMap.value = {};
  }
  dialogVisible.value = true;
};
// é‡ç½®è¡¨å•
const resetForm = () => {
  formState.value = {
    id: undefined,
    productId: undefined,
    productModelId: undefined,
    productName: "",
    productModelName: "",
    unit: "",
    type: undefined,
    qualitity: 0,
    batchNo: null,
    recordType: "",
    remark: "",
    maxStock: 0,
  };
  batchNoList.value = [];
  batchNoStockMap.value = {};
};
// å…³é—­å¯¹è¯æ¡†
const closeDialog = () => {
  dialogVisible.value = false;
  resetForm();
};
// äº§å“é€‰æ‹©å¤„理
const handleProductSelect = async products => {
  if (products && products.length > 0) {
    const product = products[0];
    formState.value.productId = product.productId;
    formState.value.productName = product.productName;
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    // ä»ŽbatchNoMaps获取批号列表和库存
    if (product.batchNoMaps && Object.keys(product.batchNoMaps).length > 0) {
      batchNoList.value = Object.keys(product.batchNoMaps);
      batchNoStockMap.value = product.batchNoMaps;
    } else {
      batchNoList.value = [];
      batchNoStockMap.value = {};
    }
    // æ¸…空已选择的批号和最大库存
    formState.value.batchNo = null;
    formState.value.maxStock = 0;
    showProductSelect.value = false;
    // è§¦å‘表单验证更新
    proxy.$refs["formRef"]?.validateField("productModelId");
  }
};
// æ‰¹å·é€‰æ‹©å˜åŒ–处理
const handleBatchNoChange = (batchNo) => {
  if (batchNo && batchNoStockMap.value[batchNo]) {
    formState.value.maxStock = batchNoStockMap.value[batchNo];
    // å¦‚果当前出库数量超过最大库存,自动调整为最大库存
    if (formState.value.qualitity > formState.value.maxStock) {
      formState.value.qualitity = formState.value.maxStock;
    }
  } else {
    formState.value.maxStock = 0;
  }
};
// æäº¤è¡¨å•
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      // éªŒè¯æ˜¯å¦é€‰æ‹©äº†äº§å“
      if (!formState.value.productModelId) {
        ElMessage.error("请选择产品");
        return;
      }
      if (dialogType.value === 'add') {
        submitAdd();
      } else {
        submitEdit();
      }
    }
  });
};
// æäº¤æ–°å¢ž
const submitAdd = () => {
  const params = { ...formState.value };
  if (formState.value.type === "qualified") {
    addStockOutRecordOnly(params).then(res => {
      ElMessage.success("新增成功");
      closeDialog();
      getList();
    }).catch(() => {
      ElMessage.error("新增失败");
    });
  } else {
    addUnqualifiedStockOutRecordOnly(params).then(res => {
      ElMessage.success("新增成功");
      closeDialog();
      getList();
    }).catch(() => {
      ElMessage.error("新增失败");
    });
  }
};
// æäº¤ç¼–辑
const submitEdit = () => {
  const params = {
    productId: formState.value.productId,
    productModelId: formState.value.productModelId,
    productName: formState.value.productName,
    model: formState.value.productModelName,
    unit: formState.value.unit,
    batchNo: formState.value.batchNo,
    stockOutNum: formState.value.qualitity,
    recordType: formState.value.recordType,
    remark: formState.value.remark,
  };
  updateStockOutRecord(formState.value.id, params).then(() => {
    ElMessage.success("编辑成功");
    closeDialog();
    getList();
  }).catch(() => {
    ElMessage.error("编辑失败");
  });
};
// èŽ·å–æ¥æºç±»åž‹é€‰é¡¹
const fetchStockRecordTypeOptions = () => {
  if (props.type === "0") {
src/views/inventoryManagement/receiptManagement/Record.vue
@@ -31,6 +31,7 @@
        </el-button>
      </div>
      <div>
        <el-button type="primary" @click="handleAdd">新增</el-button>
        <el-button type="primary" @click="handleBatchApprove">审批</el-button>
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger"
@@ -97,6 +98,17 @@
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="120" align="center" fixed="right">
          <template #default="scope">
            <el-button
              v-if="scope.row.approvalStatus !== 1 && scope.row.approvalStatus !== '1' && scope.row.approvalStatus !== 'approved' && scope.row.approvalStatus !== 'APPROVED'"
              link
              type="primary"
              size="small"
              @click="handleEdit(scope.row)">编辑</el-button>
            <span v-else style="color: #999; font-size: 12px;">已通过</span>
          </template>
        </el-table-column>
      </el-table>
      <pagination v-show="total > 0"
                  :total="total"
@@ -105,27 +117,155 @@
                  :limit="page.size"
                  @pagination="pageProductChange"/>
    </div>
    <!-- æ–°å¢ž/编辑对话框 -->
    <el-dialog v-model="dialogVisible"
               :title="dialogTitle"
               width="800"
               @close="closeDialog">
      <el-form ref="formRef"
               :model="formState"
               label-width="140px"
               label-position="top">
        <el-form-item label="产品名称"
                      prop="productModelId"
                      :rules="[
                        {
                          required: true,
                          message: '请选择产品',
                          trigger: 'change',
                        }
                      ]">
          <el-button type="primary"
                     @click="showProductSelect = true">
            {{ formState.productName ? formState.productName : '选择产品' }}
          </el-button>
        </el-form-item>
        <el-form-item label="规格"
                      prop="productModelName">
          <el-input v-model="formState.productModelName" disabled />
        </el-form-item>
        <el-form-item label="单位"
                      prop="unit">
          <el-input v-model="formState.unit" disabled />
        </el-form-item>
        <el-form-item label="库存类型"
                      prop="type"
                      :rules="[
                        {
                          required: true,
                          message: '请选择库存类型',
                          trigger: 'change',
                        }
                      ]">
          <el-select v-model="formState.type"
                     placeholder="请选择库存类型"
                     :disabled="isEdit">
            <el-option label="合格库存"
                       value="qualified" />
            <el-option label="不合格库存"
                       value="unqualified" />
          </el-select>
        </el-form-item>
        <el-form-item label="库存数量"
                      prop="qualitity">
          <el-input-number v-model="formState.qualitity"
                           :step="1"
                           :min="1"
                           style="width: 100%" />
        </el-form-item>
        <el-form-item label="批号"
                      prop="batchNo">
          <el-input v-model="formState.batchNo"
                    placeholder="请输入批号"
                    :disabled="isEdit" />
        </el-form-item>
        <el-form-item label="库位"
                      prop="warehouseId"
                      :rules="[
                        {
                          required: true,
                          message: '请选择库位',
                          trigger: 'change',
                        }
                      ]">
          <el-select v-model="formState.warehouseId"
                     placeholder="请选择库位"
                     clearable
                     style="width: 100%">
            <el-option v-for="warehouse in warehouseList"
                       :key="warehouse.id"
                       :label="warehouse.warehouseName + ' - ' + warehouse.location"
                       :value="warehouse.id" />
          </el-select>
        </el-form-item>
        <el-form-item v-if="isEdit"
                      label="来源"
                      prop="recordType">
          <el-select v-model="formState.recordType"
                     placeholder="请选择来源"
                     disabled>
            <el-option v-for="item in stockRecordTypeOptions"
                       :key="item.value"
                       :label="item.label"
                       :value="item.value" />
          </el-select>
        </el-form-item>
        <el-form-item v-if="formState.type === 'qualified'"
                      label="库存预警数量"
                      prop="warnNum">
          <el-input-number v-model="formState.warnNum"
                           :step="1"
                           :min="0"
                           :max="formState.qualitity"
                           style="width: 100%" />
        </el-form-item>
        <el-form-item label="备注"
                      prop="remark">
          <el-input v-model="formState.remark"
                    type="textarea" />
        </el-form-item>
      </el-form>
      <!-- äº§å“é€‰æ‹©å¼¹çª— -->
      <ProductSelectDialog v-model="showProductSelect"
                           @confirm="handleProductSelect"
                           :top-product-parent-id="topParentProductId"
                           single />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
          <el-button @click="closeDialog">取消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import pagination from "@/components/PIMTable/Pagination.vue";
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import {
  ref,
  reactive,
  toRefs,
  onMounted,
  getCurrentInstance,
  computed,
  watch,
} from "vue";
import {ElMessageBox} from "element-plus";
import { ElMessageBox, ElMessage } from "element-plus";
import {
  getStockInRecordListPage,
  batchDeletePendingStockInRecords,
  batchApproveStockInRecords,
  updateStockInRecord,
} from "@/api/inventoryManagement/stockInRecord.js";
import { addStockInRecordOnly } from "@/api/inventoryManagement/stockInventory.js";
import { createStockUnInventory } from "@/api/inventoryManagement/stockUninventory.js";
import {
  findAllQualifiedStockInRecordTypeOptions, findAllUnQualifiedStockInRecordTypeOptions,
} from "@/api/basicData/enum.js";
import { getWarehouseList } from "@/api/inventoryManagement/warehouse.js";
const {proxy} = getCurrentInstance();
@@ -146,6 +286,8 @@
const tableLoading = ref(false);
// æ¥æºç±»åž‹é€‰é¡¹
const stockRecordTypeOptions = ref([]);
// ä»“库列表
const warehouseList = ref([]);
const page = reactive({
  current: 1,
  size: 10,
@@ -160,6 +302,42 @@
  },
});
const {searchForm} = toRefs(data);
// å¯¹è¯æ¡†ç›¸å…³
const dialogVisible = ref(false);
const dialogType = ref('add'); // 'add' æˆ– 'edit'
const dialogTitle = computed(() => dialogType.value === 'add' ? '新增入库记录' : '编辑入库记录');
const isEdit = computed(() => dialogType.value === 'edit');
const formRef = ref();
const showProductSelect = ref(false);
// è¡¨å•数据(仿照New.vue使用formState)
const formState = ref({
  id: undefined,
  productId: undefined,
  productModelId: undefined,
  productName: "",
  productModelName: "",
  unit: "",
  type: undefined,
  qualitity: 0,
  batchNo: null,
  warehouseId: undefined,
  warnNum: 0,
  recordType: "",
  remark: "",
});
// æ‰¹å·ä¸ºç©ºæ—¶è½¬ä¸º null
watch(
  () => formState.value.batchNo,
  val => {
    if (val === "") {
      formState.value.batchNo = null;
    }
  }
);
// æŸ¥è¯¢åˆ—表
/** æœç´¢æŒ‰é’®æ“ä½œ */
const handleQuery = () => {
@@ -249,6 +427,155 @@
const expandedRowKeys = ref([]);
// æ–°å¢ž
const handleAdd = () => {
  dialogType.value = 'add';
  resetForm();
  // æ ¹æ®å½“前tab设置默认库存类型
  formState.value.type = props.type === '0' ? 'qualified' : 'unqualified';
  dialogVisible.value = true;
};
// ç¼–辑
const handleEdit = (row) => {
  dialogType.value = 'edit';
  resetForm();
  // å¡«å……表单数据
  formState.value = {
    id: row.id,
    productId: row.productId,
    productModelId: row.productModelId,
    productName: row.productName,
    productModelName: row.model,
    unit: row.unit,
    type: props.type === '0' ? 'qualified' : 'unqualified',
    qualitity: row.stockInNum,
    batchNo: row.batchNo,
    warehouseId: row.warehouseId,
    warnNum: row.warnNum || 0,
    recordType: row.recordType,
    remark: row.remark || "",
  };
  dialogVisible.value = true;
};
// é‡ç½®è¡¨å•
const resetForm = () => {
  formState.value = {
    id: undefined,
    productId: undefined,
    productModelId: undefined,
    productName: "",
    productModelName: "",
    unit: "",
    type: undefined,
    qualitity: 0,
    batchNo: null,
    warehouseId: undefined,
    warnNum: 0,
    recordType: "",
    remark: "",
  };
};
// å…³é—­å¯¹è¯æ¡†
const closeDialog = () => {
  dialogVisible.value = false;
  resetForm();
};
// äº§å“é€‰æ‹©å¤„理(仿照New.vue)
const handleProductSelect = async products => {
  if (products && products.length > 0) {
    const product = products[0];
    formState.value.productId = product.productId;
    formState.value.productName = product.productName;
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    showProductSelect.value = false;
    // è§¦å‘表单验证更新
    proxy.$refs["formRef"]?.validateField("productModelId");
  }
};
// æäº¤è¡¨å•(仿照New.vue)
const handleSubmit = () => {
  proxy.$refs["formRef"].validate(valid => {
    if (valid) {
      // éªŒè¯æ˜¯å¦é€‰æ‹©äº†äº§å“å’Œè§„æ ¼
      if (!formState.value.productModelId) {
        ElMessage.error("请选择产品");
        return;
      }
      if (dialogType.value === 'add') {
        submitAdd();
      } else {
        submitEdit();
      }
    }
  });
};
// æäº¤æ–°å¢ž
const submitAdd = () => {
  const params = { ...formState.value };
  if (formState.value.type === "qualified") {
    addStockInRecordOnly(params).then(res => {
      ElMessage.success("新增成功");
      closeDialog();
      getList();
    }).catch(() => {
      ElMessage.error("新增失败");
    });
  } else {
    params.warnNum = 0;
    createStockUnInventory(params).then(res => {
      ElMessage.success("新增成功");
      closeDialog();
      getList();
    }).catch(() => {
      ElMessage.error("新增失败");
    });
  }
};
// èŽ·å–ä»“åº“åˆ—è¡¨
const fetchWarehouseList = () => {
  getWarehouseList({ status: true }).then(res => {
    warehouseList.value = res.data || [];
  }).catch(() => {
    ElMessage.error("获取仓库列表失败");
  });
};
// æäº¤ç¼–辑
const submitEdit = () => {
  const params = {
    productId: formState.value.productId,
    productModelId: formState.value.productModelId,
    productName: formState.value.productName,
    model: formState.value.productModelName,
    unit: formState.value.unit,
    batchNo: formState.value.batchNo,
    warehouseId: formState.value.warehouseId,
    stockInNum: formState.value.qualitity,
    recordType: formState.value.recordType,
    remark: formState.value.remark,
    warnNum: formState.value.warnNum,
  };
  updateStockInRecord(formState.value.id, params).then(() => {
    ElMessage.success("编辑成功");
    closeDialog();
    getList();
  }).catch(() => {
    ElMessage.error("编辑失败");
  });
};
const handleBatchApprove = () => {
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择数据");
@@ -334,6 +661,7 @@
onMounted(() => {
  getList();
  fetchStockRecordTypeOptions();
  fetchWarehouseList();
});
watch(
@@ -346,6 +674,3 @@
</script>
<style scoped lang="scss"></style>
src/views/inventoryManagement/stockManagement/Record.vue
@@ -34,8 +34,9 @@
        <el-table-column label="库存预警数量" prop="warnNum"  show-overflow-tooltip />
        <el-table-column label="备注" prop="remark"  show-overflow-tooltip />
        <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" min-width="90" align="center">
        <el-table-column fixed="right" label="操作" min-width="120" align="center">
          <template #default="scope">
            <el-button link type="primary" @click="showEditModal(scope.row)">编辑</el-button>
            <el-button link type="primary" @click="showSubtractModal(scope.row)" :disabled="((scope.row.qualifiedUnLockedQuantity || 0) + (scope.row.qualifiedPendingOutQuantity || 0) <= 0) && ((scope.row.unQualifiedUnLockedQuantity || 0) + (scope.row.unQualifiedPendingOutQuantity || 0) <= 0)">领用</el-button>
            <el-button link type="primary" v-if="scope.row.unQualifiedUnLockedQuantity > 0 || scope.row.qualifiedUnLockedQuantity > 0" @click="showFrozenModal(scope.row)">冻结</el-button>
            <el-button link type="primary" v-if="scope.row.qualifiedLockedQuantity > 0 || scope.row.unQualifiedLockedQuantity > 0" @click="showThawModal(scope.row)">解冻</el-button>
@@ -48,6 +49,11 @@
    <new-stock-inventory v-if="isShowNewModal"
                 v-model:visible="isShowNewModal"
                 :top-product-parent-id="props.productId"
                 @completed="handleQuery" />
    <edit-stock-inventory
                 v-model:visible="isShowEditModal"
                 :record="record"
                 @completed="handleQuery" />
    <subtract-stock-inventory v-if="isShowSubtractModal"
@@ -86,6 +92,7 @@
});
const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue"));
const EditStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Edit.vue"));
const SubtractStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Subtract.vue"));
const ImportStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/Import.vue"));
const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/FrozenAndThaw.vue"));
@@ -101,6 +108,8 @@
const total = ref(0)
// æ˜¯å¦æ˜¾ç¤ºæ–°å¢žå¼¹æ¡†
const isShowNewModal = ref(false)
// æ˜¯å¦æ˜¾ç¤ºç¼–辑弹框
const isShowEditModal = ref(false)
// æ˜¯å¦æ˜¾ç¤ºé¢†ç”¨å¼¹æ¡†
const isShowSubtractModal = ref(false)
// æ˜¯å¦æ˜¾ç¤ºå†»ç»“/解冻弹框
@@ -152,6 +161,12 @@
  }
};
// ç‚¹å‡»ç¼–辑
const showEditModal = (row) => {
  record.value = row
  isShowEditModal.value = true
}
// ç‚¹å‡»é¢†ç”¨
const showSubtractModal = (row) => {
  record.value = row
src/views/inventoryManagement/warehouseManagement/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,491 @@
<template>
  <div class="app-container">
    <div class="search_form" style="margin-bottom: 10px">
      <div>
        <span class="search_title">仓库名称:</span>
        <el-input
          v-model="searchForm.warehouseName"
          placeholder="请输入仓库名称"
          clearable
          style="width: 200px"
          @keyup.enter="handleQuery"
        />
        <span class="search_title ml10">仓库位置:</span>
        <el-input
          v-model="searchForm.location"
          placeholder="请输入仓库位置"
          clearable
          style="width: 200px"
          @keyup.enter="handleQuery"
        />
        <span class="search_title ml10">负责人:</span>
        <el-input
          v-model="searchForm.managerName"
          placeholder="请输入负责人"
          clearable
          style="width: 200px"
          @keyup.enter="handleQuery"
        />
        <el-button type="primary" @click="handleQuery" style="margin-left: 10px"
          >搜索</el-button
        >
        <el-button @click="handleReset">重置</el-button>
      </div>
      <div>
        <el-button type="primary" @click="handleAdd">新增</el-button>
        <el-button type="danger" plain @click="handleDelete">删除</el-button>
      </div>
    </div>
    <div class="table_list">
      <el-table
        :data="tableData"
        border
        v-loading="tableLoading"
        @selection-change="handleSelectionChange"
        style="width: 100%"
        height="calc(100vh - 18.5em)"
      >
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column
          label="仓库名称"
          prop="warehouseName"
          min-width="150"
          show-overflow-tooltip
        />
        <el-table-column
          label="仓库位置"
          prop="location"
          min-width="200"
          show-overflow-tooltip
        />
        <el-table-column
          label="负责人"
          prop="managerName"
          min-width="120"
          show-overflow-tooltip
        />
        <el-table-column
          label="联系电话"
          prop="contactPhone"
          min-width="150"
          show-overflow-tooltip
        />
        <el-table-column label="状态" prop="status" width="100" align="center">
          <template #default="scope">
            <el-tag :type="scope.row.status ? 'success' : 'info'" size="small">
              {{ scope.row.status ? '启用' : '停用' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column
          label="创建时间"
          prop="createTime"
          min-width="180"
          show-overflow-tooltip
        />
        <el-table-column label="操作" width="150" align="center" fixed="right">
          <template #default="scope">
            <el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
            <el-button link type="danger" size="small" @click="handleRowDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
        :total="total"
        layout="total, sizes, prev, pager, next, jumper"
        :page="page.current"
        :limit="page.size"
        @pagination="paginationChange"
      />
    </div>
    <!-- æ–°å¢ž/编辑对话框 -->
    <el-dialog
      v-model="dialogVisible"
      :title="dialogTitle"
      width="600"
      @close="closeDialog"
    >
      <el-form
        ref="formRef"
        :model="formState"
        label-width="100px"
        :rules="formRules"
      >
        <el-form-item label="仓库名称" prop="warehouseName">
          <el-input
            v-model="formState.warehouseName"
            placeholder="请输入仓库名称"
            maxlength="50"
            show-word-limit
          />
        </el-form-item>
        <el-form-item label="仓库位置" prop="location">
          <el-input
            v-model="formState.location"
            placeholder="请输入仓库位置"
            maxlength="200"
            show-word-limit
          />
        </el-form-item>
        <el-form-item label="负责人" prop="managerId">
          <el-select
            v-model="formState.managerId"
            placeholder="请选择负责人"
            clearable
            filterable
            style="width: 100%"
            @change="handleManagerChange"
          >
            <el-option
              v-for="user in userList"
              :key="user.userId"
              :label="user.nickName"
              :value="user.userId"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="联系电话" prop="contactPhone">
          <el-input
            v-model="formState.contactPhone"
            placeholder="请输入联系电话"
            maxlength="20"
            show-word-limit
          />
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="formState.status">
            <el-radio :value="true">启用</el-radio>
            <el-radio :value="false">停用</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">确认</el-button>
          <el-button @click="closeDialog">取消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import pagination from "@/components/PIMTable/Pagination.vue";
import { ref, reactive, computed, getCurrentInstance, onMounted } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";
import {
  getWarehousePage,
  addWarehouse,
  updateWarehouse,
  delWarehouse,
  updateWarehouseStatus,
} from "@/api/inventoryManagement/warehouse.js";
import { listUser } from "@/api/system/user.js";
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const selectedRows = ref([]);
const tableLoading = ref(false);
const page = reactive({
  current: 1,
  size: 10,
});
const total = ref(0);
// æœç´¢è¡¨å•
const searchForm = reactive({
  warehouseName: "",
  location: "",
  managerName: "",
});
// å¯¹è¯æ¡†ç›¸å…³
const dialogVisible = ref(false);
const dialogType = ref("add"); // 'add' æˆ– 'edit'
const dialogTitle = computed(() =>
  dialogType.value === "add" ? "新增仓库" : "编辑仓库"
);
const isEdit = computed(() => dialogType.value === "edit");
const formRef = ref();
// è¡¨å•数据
const formState = reactive({
  id: undefined,
  warehouseName: "",
  location: "",
  managerId: undefined,
  managerName: "",
  contactPhone: "",
  status: true,
});
// ç”¨æˆ·åˆ—表
const userList = ref([]);
// è¡¨å•验证规则
const formRules = {
  warehouseName: [
    { required: true, message: "请输入仓库名称", trigger: "blur" },
    { min: 1, max: 50, message: "长度在 1 åˆ° 50 ä¸ªå­—符", trigger: "blur" },
  ],
  location: [
    { required: true, message: "请输入仓库位置", trigger: "blur" },
    { min: 1, max: 200, message: "长度在 1 åˆ° 200 ä¸ªå­—符", trigger: "blur" },
  ],
  managerId: [
    { required: true, message: "请选择负责人", trigger: "change" },
  ],
  contactPhone: [
    { required: true, message: "请输入联系电话", trigger: "blur" },
    { pattern: /^1[3-9]\d{9}$|^0\d{2,3}-?\d{7,8}$/, message: "请输入正确的电话号码", trigger: "blur" },
  ],
  status: [{ required: true, message: "请选择状态", trigger: "change" }],
};
// èŽ·å–ç”¨æˆ·åˆ—è¡¨
const getUserList = () => {
  listUser({ pageNum: 1, pageSize: 1000 }).then((res) => {
    userList.value = res.rows || [];
  });
};
// è´Ÿè´£äººé€‰æ‹©å˜åŒ–
const handleManagerChange = (userId) => {
  const user = userList.value.find((item) => item.userId === userId);
  if (user) {
    formState.managerName = user.nickName;
  } else {
    formState.managerName = "";
  }
};
// æŸ¥è¯¢åˆ—表
const handleQuery = () => {
  page.current = 1;
  getList();
};
// é‡ç½®æœç´¢
const handleReset = () => {
  searchForm.warehouseName = "";
  searchForm.location = "";
  searchForm.managerName = "";
  handleQuery();
};
const paginationChange = (obj) => {
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
const getList = () => {
  tableLoading.value = true;
  getWarehousePage({
    ...searchForm,
    current: page.current,
    size: page.size,
  })
    .then((res) => {
      tableLoading.value = false;
      tableData.value = res.data.records || [];
      total.value = res.data.total || 0;
    })
    .catch(() => {
      tableLoading.value = false;
    });
};
// æ–°å¢ž
const handleAdd = () => {
  dialogType.value = "add";
  resetForm();
  dialogVisible.value = true;
};
// ç¼–辑
const handleEdit = (row) => {
  dialogType.value = "edit";
  resetForm();
  // æ ¹æ®managerName查找对应的managerId
  const user = userList.value.find((item) => item.nickName === row.managerName);
  // å¡«å……表单数据
  Object.assign(formState, {
    id: row.id,
    warehouseName: row.warehouseName,
    location: row.location,
    managerId: user ? user.userId : row.managerId,
    managerName: row.managerName,
    contactPhone: row.contactPhone,
    status: row.status,
  });
  dialogVisible.value = true;
};
// é‡ç½®è¡¨å•
const resetForm = () => {
  formState.id = undefined;
  formState.warehouseName = "";
  formState.location = "";
  formState.managerId = undefined;
  formState.managerName = "";
  formState.contactPhone = "";
  formState.status = true;
  proxy.$refs["formRef"]?.resetFields();
};
// å…³é—­å¯¹è¯æ¡†
const closeDialog = () => {
  dialogVisible.value = false;
  resetForm();
};
// æäº¤è¡¨å•
const handleSubmit = () => {
  proxy.$refs["formRef"].validate((valid) => {
    if (valid) {
      if (dialogType.value === "add") {
        submitAdd();
      } else {
        submitEdit();
      }
    }
  });
};
// æäº¤æ–°å¢ž
const submitAdd = () => {
  const params = { ...formState };
  delete params.id;
  addWarehouse(params)
    .then(() => {
      ElMessage.success("新增成功");
      closeDialog();
      getList();
    })
    .catch(() => {
      ElMessage.error("新增失败");
    });
};
// æäº¤ç¼–辑
const submitEdit = () => {
  const params = { ...formState };
  updateWarehouse(params)
    .then(() => {
      ElMessage.success("编辑成功");
      closeDialog();
      getList();
    })
    .catch(() => {
      ElMessage.error("编辑失败");
    });
};
// çŠ¶æ€å˜æ›´
const handleStatusChange = (row) => {
  const statusText = row.status ? "启用" : "停用";
  ElMessageBox.confirm(
    `确认要${statusText}该仓库吗?`,
    "提示",
    {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    }
  )
    .then(() => {
      updateWarehouseStatus(row.id, row.status)
        .then(() => {
          ElMessage.success(`${statusText}成功`);
          getList();
        })
        .catch(() => {
          // æ¢å¤åŽŸçŠ¶æ€
          row.status = !row.status;
          ElMessage.error(`${statusText}失败`);
        });
    })
    .catch(() => {
      // æ¢å¤åŽŸçŠ¶æ€
      row.status = !row.status;
      ElMessage.info("已取消");
    });
};
// è¡¨æ ¼é€‰æ‹©æ•°æ®
const handleSelectionChange = (selection) => {
  selectedRows.value = selection;
};
// æ‰¹é‡åˆ é™¤
const handleDelete = () => {
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择要删除的数据");
    return;
  }
  const ids = selectedRows.value.map((item) => item.id);
  ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      delWarehouse(ids).then(() => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// å•行删除
const handleRowDelete = (row) => {
  ElMessageBox.confirm("确认删除该仓库吗?", "提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      delWarehouse([row.id]).then(() => {
        proxy.$modal.msgSuccess("删除成功");
        getList();
      });
    })
    .catch(() => {
      proxy.$modal.msg("已取消");
    });
};
// åˆå§‹åŒ–加载数据
onMounted(() => {
  getList();
  getUserList();
});
</script>
<style scoped>
.search_form {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.search_title {
  font-size: 14px;
  color: #606266;
}
.ml10 {
  margin-left: 10px;
}
.table_list {
  margin-top: 10px;
}
</style>
src/views/procurementManagement/procurementLedger/index.vue
@@ -394,15 +394,6 @@
                           prop="taxExclusiveTotalPrice"
                           :formatter="formattedNumber"
                           width="150" />
          <el-table-column label="是否质检"
                           prop="isChecked"
                           width="150">
            <template #default="scope">
              <el-tag :type="scope.row.isChecked ? 'success' : 'info'">
                {{ scope.row.isChecked ? '是' : '否' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column fixed="right"
                           label="操作"
                           min-width="60"
@@ -615,19 +606,6 @@
                               :min="0"
                               clearable
                               style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="是否质检:"
                          prop="isChecked">
              <el-radio-group v-model="productForm.isChecked">
                <el-radio label="是"
                          :value="true" />
                <el-radio label="否"
                          :value="false" />
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
@@ -852,7 +830,6 @@
      supplierId: "",
      paymentMethod: "",
      executionDate: "",
      isChecked: false,
    },
    rules: {
      purchaseContractNumber: [
@@ -897,7 +874,6 @@
      taxExclusiveTotalPrice: "",
      invoiceType: "",
      warnNum: "",
      isChecked: false,
    },
    productRules: {
      productId: [{ required: true, message: "请选择", trigger: "change" }],
@@ -916,7 +892,6 @@
        { required: true, message: "请输入", trigger: "blur" },
      ],
      invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
      isChecked: [{ required: true, message: "请选择", trigger: "change" }],
    },
  });
  const { productForm, productRules } = toRefs(productFormData);
@@ -1386,9 +1361,7 @@
    // ç­‰å¾… DOM æ›´æ–°
    await nextTick();
    if (type === "add") {
      productForm.value.isChecked = false;
    }
    if (type === "edit") {
      // å¤åˆ¶è¡Œæ•°æ®
src/views/salesManagement/salesLedger/index.vue
@@ -451,15 +451,6 @@
          <el-table-column label="不含税总价(元)"
                           prop="taxExclusiveTotalPrice"
                           :formatter="formattedNumber" />
          <el-table-column label="是否生产"
                           prop="isProduction"
                           width="150">
            <template #default="scope">
              <el-tag :type="scope.row.isProduction ? 'success' : 'info'">
                {{ scope.row.isProduction ? '是' : '否' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column fixed="right"
                           label="操作"
                           min-width="60"
@@ -706,17 +697,6 @@
                <el-option label="增专票"
                           value="增专票" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否生产:"
                          prop="isProduction">
              <el-radio-group v-model="productForm.isProduction">
                <el-radio label="是"
                          :value="true" />
                <el-radio label="否"
                          :value="false" />
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
@@ -1105,7 +1085,6 @@
      taxInclusiveTotalPrice: "",
      taxExclusiveTotalPrice: "",
      invoiceType: "",
      isProduction: false,
    },
    productRules: {
      productCategory: [{ required: true, message: "请选择", trigger: "change" }],
@@ -1126,7 +1105,6 @@
        { required: true, message: "请输入", trigger: "blur" },
      ],
      invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
      isProduction: [{ required: true, message: "请选择", trigger: "change" }],
    },
  });
  const { productForm, productRules } = toRefs(productFormData);
@@ -1754,9 +1732,6 @@
    productOperationType.value = type;
    productForm.value = {};
    if (type === "add") {
      productForm.value.isProduction = true;
    }
    proxy.resetForm("productFormRef");
    if (type === "edit") {
      productForm.value = { ...row };