Browse Source

供应商管理 生产厂商管理 修改

HuRongxin 1 month ago
parent
commit
30a666f997

+ 63 - 0
src/api/warehouse/productManufacturer/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ManufacturerVO, ManufacturerForm, ManufacturerQuery } from '@/api/warehouse/productManufacturer/types';
+
+/**
+ * 查询生产产商列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listManufacturer = (query?: ManufacturerQuery): AxiosPromise<ManufacturerVO[]> => {
+  return request({
+    url: '/warehouse/productManufacturer/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询生产产商详细
+ * @param id
+ */
+export const getManufacturer = (id: string | number): AxiosPromise<ManufacturerVO> => {
+  return request({
+    url: '/warehouse/productManufacturer/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增生产产商
+ * @param data
+ */
+export const addManufacturer = (data: ManufacturerForm) => {
+  return request({
+    url: '/warehouse/productManufacturer',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改生产产商
+ * @param data
+ */
+export const updateManufacturer = (data: ManufacturerForm) => {
+  return request({
+    url: '/warehouse/productManufacturer',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除生产产商
+ * @param id
+ */
+export const delManufacturer = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/warehouse/productManufacturer/' + id,
+    method: 'delete'
+  });
+};

+ 101 - 0
src/api/warehouse/productManufacturer/types.ts

@@ -0,0 +1,101 @@
+export interface ManufacturerVO {
+  /**
+   * 
+   */
+  id: string | number;
+
+  /**
+   * 生产产商
+   */
+  name: string;
+
+  /**
+   * 联系人名称
+   */
+  contactName: string;
+
+  /**
+   * 联系人电话
+   */
+  contactPhone: string;
+
+  /**
+   * 联系人地址
+   */
+  address: string;
+
+  /**
+   * 描述
+   */
+  description: string;
+
+}
+
+export interface ManufacturerForm extends BaseEntity {
+  /**
+   * 
+   */
+  id?: string | number;
+
+  /**
+   * 生产产商
+   */
+  name?: string;
+
+  /**
+   * 联系人名称
+   */
+  contactName?: string;
+
+  /**
+   * 联系人电话
+   */
+  contactPhone?: string;
+
+  /**
+   * 联系人地址
+   */
+  address?: string;
+
+  /**
+   * 描述
+   */
+  description?: string;
+
+}
+
+export interface ManufacturerQuery extends PageQuery {
+
+  /**
+   * 生产产商
+   */
+  name?: string;
+
+  /**
+   * 联系人名称
+   */
+  contactName?: string;
+
+  /**
+   * 联系人电话
+   */
+  contactPhone?: string;
+
+  /**
+   * 联系人地址
+   */
+  address?: string;
+
+  /**
+   * 描述
+   */
+  description?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 0 - 1
src/api/warehouse/productNutrition/types.ts

@@ -662,7 +662,6 @@ export interface NutritionForm extends BaseEntity {
 
     productLabelList?: string[];
 
-    contraindicationLabelList?: string[];
 
     /**
      * 禁忌症所属标签

+ 63 - 0
src/api/warehouse/productSupplier/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { SupplierVO, SupplierForm, SupplierQuery } from '@/api/warehouse/productSupplier/types';
+
+/**
+ * 查询供应商列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSupplier = (query?: SupplierQuery): AxiosPromise<SupplierVO[]> => {
+  return request({
+    url: '/warehouse/productSupplier/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询供应商详细
+ * @param id
+ */
+export const getSupplier = (id: string | number): AxiosPromise<SupplierVO> => {
+  return request({
+    url: '/warehouse/productSupplier/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增供应商
+ * @param data
+ */
+export const addSupplier = (data: SupplierForm) => {
+  return request({
+    url: '/warehouse/productSupplier',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改供应商
+ * @param data
+ */
+export const updateSupplier = (data: SupplierForm) => {
+  return request({
+    url: '/warehouse/productSupplier',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除供应商
+ * @param id
+ */
+export const delSupplier = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/warehouse/productSupplier/' + id,
+    method: 'delete'
+  });
+};

+ 101 - 0
src/api/warehouse/productSupplier/types.ts

@@ -0,0 +1,101 @@
+export interface SupplierVO {
+  /**
+   * 
+   */
+  id: string | number;
+
+  /**
+   * 供应商
+   */
+  name: string;
+
+  /**
+   * 联系人名称
+   */
+  contactName: string;
+
+  /**
+   * 联系人电话
+   */
+  contactPhone: string;
+
+  /**
+   * 联系人地址
+   */
+  address: string;
+
+  /**
+   * 描述
+   */
+  description: string;
+
+}
+
+export interface SupplierForm extends BaseEntity {
+  /**
+   * 
+   */
+  id?: string | number;
+
+  /**
+   * 供应商
+   */
+  name?: string;
+
+  /**
+   * 联系人名称
+   */
+  contactName?: string;
+
+  /**
+   * 联系人电话
+   */
+  contactPhone?: string;
+
+  /**
+   * 联系人地址
+   */
+  address?: string;
+
+  /**
+   * 描述
+   */
+  description?: string;
+
+}
+
+export interface SupplierQuery extends PageQuery {
+
+  /**
+   * 供应商
+   */
+  name?: string;
+
+  /**
+   * 联系人名称
+   */
+  contactName?: string;
+
+  /**
+   * 联系人电话
+   */
+  contactPhone?: string;
+
+  /**
+   * 联系人地址
+   */
+  address?: string;
+
+  /**
+   * 描述
+   */
+  description?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 592 - 535
src/views/warehouse/nutriProduct/index.vue

@@ -162,14 +162,14 @@
                                 <el-col :span="12">
                                     <el-form-item label="生产厂商:" prop="manufacturer">
                                         <el-select v-model="form.manufacturer" placeholder="请选择" clearable>
-                                            <el-option v-for="dict in product_manufacturer" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                            <el-option v-for="item in productManufacturerList" :key="item.value" :label="item.label" :value="item.value" />
                                         </el-select>
                                     </el-form-item>
                                 </el-col>
                                 <el-col :span="12">
                                     <el-form-item label="供应商:" prop="supplier">
                                         <el-select v-model="form.supplier" placeholder="请选择" clearable>
-                                            <el-option v-for="dict in product_supplier" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                            <el-option v-for="item in productSupplierList" :key="item.value" :label="item.label" :value="item.value" />
                                         </el-select>
                                     </el-form-item>
                                 </el-col>
@@ -1036,7 +1036,7 @@
                                 <div><b><span style="color:red;margin-right: 3px">*</span>院方系统编码:</b>{{ form.hospitalSystemCode || '--' }}</div>
                                 <div><b><span style="color:red;margin-right: 3px">*</span>商品编码:</b>{{ form.productCode || '--' }}</div>
                                 <div><b><span style="color:red;margin-right: 3px">*</span>产品所属分类:</b>{{ form.productCategory || '--' }}</div>
-                                <div><b>生产厂商:</b>{{ getDictLabel(product_manufacturer, form.manufacturer) || '--' }}</div>
+                                <div><b>生产厂商:</b>{{ productManufacturerList.find(item => item.value === form.manufacturer)?.label || '--' }}</div>
                                 <div><b>品牌:</b>{{ form.brand || '--' }}</div>
                                 <div><b>产品所属标签:</b>{{ form.productLabel || '--' }}</div>
                                 <div><b>许可证临期提醒:</b>{{ form.licenseExpiryReminder || '--' }}</div>
@@ -1047,7 +1047,7 @@
                                 <div><b>批准文号:</b>{{ form.approvalNumber || '--' }}</div>
                                 <div><b>口味:</b>{{ form.taste || '--' }}</div>
                                 <div><b>剂型/形态:</b>{{ getDictLabel(dosage_form, form.dosageForm) || '--' }}</div>
-                                <div><b>供应商:</b>{{ getDictLabel(product_supplier, form.supplier) || '--' }}</div>
+                                <div><b>供应商:</b>{{ productSupplierList.find(item => item.value === form.supplier)?.label || '--' }}</div>
                                 <div><b>产品适用科室:</b>{{ form.applicableDepartment|| '--'  }}</div>
                                 <div><b>禁忌症所属标签:</b>{{ form.contraindicationLabel || '--' }}</div>
                                 <div><b><span style="color:red;margin-right: 3px">*</span>保质期临期提醒:</b>{{ form.shelfLifeReminder || '--' }}</div>
@@ -1430,573 +1430,630 @@
             </div>
         </el-dialog>
         <!-- 添加疾病标签弹窗 -->
-        <LabelDialog
-            v-model="diseaseLabelDialogVisible"
-            :initial-selected-labels="form.productLabelList || []"
-            @confirm="onLabelConfirm"
-        />
+        <LabelDialog v-model="diseaseLabelDialogVisible" :initial-selected-labels="form.productLabelList || []" @confirm="onLabelConfirm" />
         <!-- 添加禁忌症标签弹窗 -->
-        <LabelDialog
-            v-model="contraindicationLabelDialogVisible"
-            :initial-selected-labels="form.contraindicationLabelList || []"
-            @confirm="onContraindicationLabelConfirm"
-        />
+        <LabelDialog v-model="contraindicationLabelDialogVisible" :initial-selected-labels="form.contraindicationLabelList || []" @confirm="onContraindicationLabelConfirm" />
     </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
-import { listNutrition, getNutrition, delNutrition, addNutrition, updateNutrition, batchUpdateNutrition } from '@/api/warehouse/productNutrition/index';
-import { NutritionVO, NutritionQuery, NutritionForm } from '@/api/warehouse/productNutrition/types';
-import { listCategory } from '@/api/warehouse/productCategory/index';
-import { listDept } from '@/api/system/dept';
-import { globalHeaders } from '@/utils/request';
-import { FormInstance, ElMessageBox, UploadFile, UploadFiles } from 'element-plus';
-import { log } from 'console';
-import LabelDialog from './labelDialog.vue';
-import FileUpload from '@/components/FileUpload/index.vue';
-
-const diseaseLabelDialogVisible = ref(false);
-const contraindicationLabelDialogVisible = ref(false);
-
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { product_qualification, dosage_form, product_package_unit, product_supplier, put_flag, product_manufacturer, default_usage, product_spec_unit } = toRefs < any > (proxy ?.useDict('product_qualification', 'dosage_form', 'product_package_unit', 'product_supplier', 'put_flag', 'product_manufacturer', 'default_usage', 'product_spec_unit'));
-
-
-const nutritionList = ref < NutritionVO[] > ([]);
-const baseUrl =
-    import.meta.env.VITE_APP_BASE_API; // 上传文件地址
-const uploadFileUrl = ref(baseUrl + 'warehouse/nutrition/importExcel');
-const buttonLoading = ref(false);
-const loading = ref(true);
-const showSearch = ref(true);
-const ids = ref < Array < string | number >> ([]);
-const single = ref(true);
-const multiple = ref(true);
-const total = ref(0);
-const headers = ref(globalHeaders()); // 请求头设置
-
-const activeTab = ref('basic');
-const detailDialogVisible = ref(false);
-const batchSetDialogVisible = ref(false);
-const fileList = ref([]); // 用于Excel导入的文件列表
-const batchSetForm = reactive({
-    shelfLifeReminder: '',
-    licenseExpiryReminder: ''
-});
-
-const batchRules = {
-    shelfLifeReminder: [{ required: true, message: "保质期临期提醒不能为空", trigger: "blur" }],
-    licenseExpiryReminder: [{ required: true, message: "许可证临期提醒不能为空", trigger: "blur" }],
-
-};
-
-const treeData = ref([]); // 定义 treeData
-const deptList = ref([]); // 定义 科室list
-
-const queryFormRef = ref < FormInstance > ();
-const nutritionFormRef = ref < FormInstance > ();
-
-const dialog = reactive < DialogOption > ({
-    visible: false,
-    title: ''
-});
-const dialogFile = reactive < DialogOption > ({
-    visible: false,
-    title: '请上传'
-});
-
-const initFormData: NutritionForm = {
-    id: undefined,
-    ids: undefined,
-    productName: undefined,
-    hospitalSystemCode: undefined,
-    productCode: undefined,
-    productCategory: undefined,
-    productCategoryList: undefined,
-    manufacturer: undefined,
-    brand: undefined,
-    licenseExpiryReminder: undefined,
-    productLicenseExpiry: undefined,
-    productQualification: undefined,
-    approvalNumber: undefined,
-    taste: undefined,
-    dosageForm: undefined,
-    supplier: undefined,
-    applicableDepartment: undefined,
-    applicableDepartmentList: undefined,
-    contraindicationLabel: undefined,
-    shelfLifeReminder: undefined,
-    shelfLife: undefined,
-    purchasePrice: undefined,
-    purchaseUnit: '2',
-    defaultUsage: '2',
-    packageUnit: '2',
-    productSpec: undefined,
-    productSpecValue: undefined,
-    productSpecUnit: '1',
-    packagePrice: undefined,
-    minUnit: '3',
-    minSpec: undefined,
-    netContent: undefined,
-    configSalePrice: undefined,
-    configLossRate: undefined,
-    calorie: undefined,
-    carbohydrate: undefined,
-    heatEnergy: undefined,
-    protein: undefined,
-    fat: undefined,
-    moisture: undefined,
-    ca: undefined,
-    p: undefined,
-    k: undefined,
-    na: undefined,
-    mg: undefined,
-    cl: undefined,
-    fe: undefined,
-    zn: undefined,
-    se: undefined,
-    cu: undefined,
-    mn: undefined,
-    i: undefined,
-    f: undefined,
-    cr: undefined,
-    mo: undefined,
-    isoleucine: undefined,
-    tryptophan: undefined,
-    sulfurAminoAcid: undefined,
-    histidine: undefined,
-    aromaticAminoAcid: undefined,
-    glutamicAcid: undefined,
-    threonine: undefined,
-    serine: undefined,
-    arginine: undefined,
-    lysine: undefined,
-    asparticAcid: undefined,
-    cysteine: undefined,
-    proline: undefined,
-    tyrosine: undefined,
-    leucine: undefined,
-    valine: undefined,
-    methionine: undefined,
-    alanine: undefined,
-    phenylalanine: undefined,
-    glycine: undefined,
-    fattyAcid: undefined,
-    saturatedFattyAcid: undefined,
-    monounsaturatedFattyAcid: undefined,
-    polyunsaturatedFattyAcid: undefined,
-    vitaminA: undefined,
-    vitaminACarotene: undefined,
-    vitaminAAlcohol: undefined,
-    vitaminD: undefined,
-    vitaminE: undefined,
-    vitaminETocopherol: undefined,
-    vitaminK: undefined,
-    vitaminBOne: undefined,
-    vitaminBTwo: undefined,
-    vitaminBSix: undefined,
-    vitaminBTwelve: undefined,
-    niacin: undefined,
-    vitaminC: undefined,
-    folicAcid: undefined,
-    choline: undefined,
-    biotin: undefined,
-    pantothenicAcid: undefined,
-    cholesterol: undefined,
-    bloodGlucoseIndex: undefined,
-    insolubleDietaryFiber: undefined,
-    dietaryFiber: undefined,
-    ash: undefined,
-    solubleDietaryFiber: undefined,
-    applicableCrowd: undefined,
-    unsuitableCrowd: undefined,
-    osmoticPressure: undefined,
-    rawMaterial: undefined,
-    indicationsContraindications: undefined,
-    usageAndDosage: undefined,
-    productFeatures: undefined,
-    storageConditions: undefined,
-    warningInstructions: undefined,
-    productAttachments: undefined,
-    productAttachmentsList: [],
-    status: undefined,
-    putFlag: undefined,
-    outboundNumber: undefined,
-    productLabel: undefined,
-    productLabelList: [],
-    contraindicationLabelList: [],
-};
-
-const data = reactive < PageData < NutritionForm,
-    NutritionQuery >> ({
-        form: { ...initFormData },
-        queryParams: {
-            pageNum: 1,
-            pageSize: 10,
-            productName: undefined,
-            productCategory: undefined,
-            productCategoryList: [],
-        },
-        rules: {
-            productName: [
-                { required: true, message: "产品名称不能为空", trigger: "blur" }
-            ],
-            hospitalSystemCode: [
-                { required: true, message: "院方系统编码不能为空", trigger: "blur" }
-            ],
-            productCode: [
-                { required: true, message: "商品编码不能为空", trigger: "blur" }
-            ],
-            productCategory: [
-                { required: true, message: "产品所属分类不能为空", trigger: "blur" }
-            ],
-            productQualification: [
-                { required: true, message: "商品资质不能为空", trigger: "blur" }
-            ],
-            shelfLifeReminder: [
-                { required: true, message: "保质期临期提醒不能为空", trigger: "blur" }
-            ],
-            shelfLife: [
-                { required: true, message: "保质期不能为空", trigger: "blur" }
-            ],
-            purchasePrice: [
-                { required: true, message: "入货价格不能为空", trigger: "blur" }
-            ],
-            purchaseUnit: [
-                { required: true, message: "入货单位不能为空", trigger: "blur" }
-            ],
-            productSpec: [
-                { required: true, message: "商品规格不能为空", trigger: "blur" }
-            ],
-            configSalePrice: [
-                { required: true, message: "配置销售价格不能为空", trigger: "blur" }
-            ],
-            packagePrice: [
-                { required: true, message: "预包装价格不能为空", trigger: "blur" }
-            ],
-        }
+    import { ref, reactive, onMounted, getCurrentInstance } from 'vue';
+    import { listNutrition, getNutrition, delNutrition, addNutrition, updateNutrition, batchUpdateNutrition } from '@/api/warehouse/productNutrition/index';
+    import { NutritionVO, NutritionQuery, NutritionForm } from '@/api/warehouse/productNutrition/types';
+    import { listCategory } from '@/api/warehouse/productCategory/index';
+    import { listDept } from '@/api/system/dept';
+    import { listSupplier } from '@/api/warehouse/productSupplier'
+    import { listManufacturer } from '@/api/warehouse/productManufacturer'
+    import { globalHeaders } from '@/utils/request';
+    import { FormInstance, ElMessageBox, UploadFile, UploadFiles } from 'element-plus';
+    import { log } from 'console';
+    import LabelDialog from './labelDialog.vue';
+    import FileUpload from '@/components/FileUpload/index.vue';
+    import { ManufacturerVO } from '@/api/warehouse/productManufacturer/types';
+    import type { SupplierQuery } from '@/api/warehouse/productSupplier/types';
+    import type { ManufacturerQuery } from '@/api/warehouse/productManufacturer/types';
+
+    const diseaseLabelDialogVisible = ref(false);
+    const contraindicationLabelDialogVisible = ref(false);
+
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+    const { product_qualification, dosage_form, product_package_unit, put_flag, default_usage, product_spec_unit } = toRefs < any > (proxy ?.useDict('product_qualification', 'dosage_form', 'product_package_unit', 'put_flag', 'default_usage', 'product_spec_unit'));
+
+
+    const nutritionList = ref < NutritionVO[] > ([]);
+    const baseUrl = import.meta.env.VITE_APP_BASE_API; // 上传文件地址
+    const uploadFileUrl = ref(baseUrl + 'warehouse/nutrition/importExcel');
+    const buttonLoading = ref(false);
+    const loading = ref(true);
+    const showSearch = ref(true);
+    const ids = ref < Array < string | number >> ([]);
+    const single = ref(true);
+    const multiple = ref(true);
+    const total = ref(0);
+    const headers = ref(globalHeaders()); // 请求头设置
+
+    const activeTab = ref('basic');
+    const detailDialogVisible = ref(false);
+    const batchSetDialogVisible = ref(false);
+    const fileList = ref([]); // 用于Excel导入的文件列表
+    const batchSetForm = reactive({
+        shelfLifeReminder: '',
+        licenseExpiryReminder: ''
     });
 
-const { queryParams, form, rules } = toRefs(data);
+    const batchRules = {
+        shelfLifeReminder: [{ required: true, message: "保质期临期提醒不能为空", trigger: "blur" }],
+        licenseExpiryReminder: [{ required: true, message: "许可证临期提醒不能为空", trigger: "blur" }],
+
+    };
 
-const categoryOptions = ref([]);
+    const treeData = ref([]); // 定义 treeData
+    const deptList = ref([]); // 定义 科室list
 
-function buildCategoryTree(flatList) {
-    const idMap = {};
-    const tree = [];
-    flatList.forEach(item => {
-        idMap[item.categoryId] = {
-            label: item.categoryName,
-            value: item.categoryId,
-            children: []
-        };
+    const queryFormRef = ref < FormInstance > ();
+    const nutritionFormRef = ref < FormInstance > ();
+
+    const dialog = reactive < DialogOption > ({
+        visible: false,
+        title: ''
     });
-    flatList.forEach(item => {
-        if (item.parentId && item.parentId !== 0 && idMap[item.parentId]) {
-            idMap[item.parentId].children.push(idMap[item.categoryId]);
-        } else if (item.parentId === 0) {
-            tree.push(idMap[item.categoryId]);
-        }
+    const dialogFile = reactive < DialogOption > ({
+        visible: false,
+        title: '请上传'
     });
-    // 去除没有children的children字段
-    function clean(node) {
-        if (node.children && node.children.length === 0) {
-            delete node.children;
-        } else if (node.children) {
-            node.children.forEach(clean);
+
+    const initFormData: NutritionForm = {
+        id: undefined,
+        ids: undefined,
+        productName: undefined,
+        hospitalSystemCode: undefined,
+        productCode: undefined,
+        productCategory: undefined,
+        productCategoryList: undefined,
+        manufacturer: undefined,
+        brand: undefined,
+        licenseExpiryReminder: undefined,
+        productLicenseExpiry: undefined,
+        productQualification: undefined,
+        approvalNumber: undefined,
+        taste: undefined,
+        dosageForm: undefined,
+        supplier: undefined,
+        applicableDepartment: undefined,
+        applicableDepartmentList: undefined,
+        contraindicationLabel: undefined,
+        shelfLifeReminder: undefined,
+        shelfLife: undefined,
+        purchasePrice: undefined,
+        purchaseUnit: '2',
+        defaultUsage: '2',
+        packageUnit: '2',
+        productSpec: undefined,
+        productSpecValue: undefined,
+        productSpecUnit: '1',
+        packagePrice: undefined,
+        minUnit: '3',
+        minSpec: undefined,
+        netContent: undefined,
+        configSalePrice: undefined,
+        configLossRate: undefined,
+        calorie: undefined,
+        carbohydrate: undefined,
+        heatEnergy: undefined,
+        protein: undefined,
+        fat: undefined,
+        moisture: undefined,
+        ca: undefined,
+        p: undefined,
+        k: undefined,
+        na: undefined,
+        mg: undefined,
+        cl: undefined,
+        fe: undefined,
+        zn: undefined,
+        se: undefined,
+        cu: undefined,
+        mn: undefined,
+        i: undefined,
+        f: undefined,
+        cr: undefined,
+        mo: undefined,
+        isoleucine: undefined,
+        tryptophan: undefined,
+        sulfurAminoAcid: undefined,
+        histidine: undefined,
+        aromaticAminoAcid: undefined,
+        glutamicAcid: undefined,
+        threonine: undefined,
+        serine: undefined,
+        arginine: undefined,
+        lysine: undefined,
+        asparticAcid: undefined,
+        cysteine: undefined,
+        proline: undefined,
+        tyrosine: undefined,
+        leucine: undefined,
+        valine: undefined,
+        methionine: undefined,
+        alanine: undefined,
+        phenylalanine: undefined,
+        glycine: undefined,
+        fattyAcid: undefined,
+        saturatedFattyAcid: undefined,
+        monounsaturatedFattyAcid: undefined,
+        polyunsaturatedFattyAcid: undefined,
+        vitaminA: undefined,
+        vitaminACarotene: undefined,
+        vitaminAAlcohol: undefined,
+        vitaminD: undefined,
+        vitaminE: undefined,
+        vitaminETocopherol: undefined,
+        vitaminK: undefined,
+        vitaminBOne: undefined,
+        vitaminBTwo: undefined,
+        vitaminBSix: undefined,
+        vitaminBTwelve: undefined,
+        niacin: undefined,
+        vitaminC: undefined,
+        folicAcid: undefined,
+        choline: undefined,
+        biotin: undefined,
+        pantothenicAcid: undefined,
+        cholesterol: undefined,
+        bloodGlucoseIndex: undefined,
+        insolubleDietaryFiber: undefined,
+        dietaryFiber: undefined,
+        ash: undefined,
+        solubleDietaryFiber: undefined,
+        applicableCrowd: undefined,
+        unsuitableCrowd: undefined,
+        osmoticPressure: undefined,
+        rawMaterial: undefined,
+        indicationsContraindications: undefined,
+        usageAndDosage: undefined,
+        productFeatures: undefined,
+        storageConditions: undefined,
+        warningInstructions: undefined,
+        productAttachments: undefined,
+        productAttachmentsList: [],
+        status: undefined,
+        putFlag: undefined,
+        outboundNumber: undefined,
+        productLabel: undefined,
+        productLabelList: [],
+        contraindicationLabelList: [],
+    };
+
+    const data = reactive < PageData < NutritionForm,
+        NutritionQuery >> ({
+            form: { ...initFormData },
+            queryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                productName: undefined,
+                productCategory: undefined,
+                productCategoryList: [],
+            },
+            rules: {
+                productName: [
+                    { required: true, message: "产品名称不能为空", trigger: "blur" }
+                ],
+                hospitalSystemCode: [
+                    { required: true, message: "院方系统编码不能为空", trigger: "blur" }
+                ],
+                productCode: [
+                    { required: true, message: "商品编码不能为空", trigger: "blur" }
+                ],
+                productCategory: [
+                    { required: true, message: "产品所属分类不能为空", trigger: "blur" }
+                ],
+                productQualification: [
+                    { required: true, message: "商品资质不能为空", trigger: "blur" }
+                ],
+                shelfLifeReminder: [
+                    { required: true, message: "保质期临期提醒不能为空", trigger: "blur" }
+                ],
+                shelfLife: [
+                    { required: true, message: "保质期不能为空", trigger: "blur" }
+                ],
+                purchasePrice: [
+                    { required: true, message: "入货价格不能为空", trigger: "blur" }
+                ],
+                purchaseUnit: [
+                    { required: true, message: "入货单位不能为空", trigger: "blur" }
+                ],
+                productSpec: [
+                    { required: true, message: "商品规格不能为空", trigger: "blur" }
+                ],
+                configSalePrice: [
+                    { required: true, message: "配置销售价格不能为空", trigger: "blur" }
+                ],
+                packagePrice: [
+                    { required: true, message: "预包装价格不能为空", trigger: "blur" }
+                ],
+            }
+        });
+
+    const { queryParams, form, rules } = toRefs(data);
+
+    const categoryOptions = ref([]);
+
+    function buildCategoryTree(flatList) {
+        const idMap = {};
+        const tree = [];
+        flatList.forEach(item => {
+            idMap[item.categoryId] = {
+                label: item.categoryName,
+                value: item.categoryId,
+                children: []
+            };
+        });
+        flatList.forEach(item => {
+            if (item.parentId && item.parentId !== 0 && idMap[item.parentId]) {
+                idMap[item.parentId].children.push(idMap[item.categoryId]);
+            } else if (item.parentId === 0) {
+                tree.push(idMap[item.categoryId]);
+            }
+        });
+        // 去除没有children的children字段
+        function clean(node) {
+            if (node.children && node.children.length === 0) {
+                delete node.children;
+            } else if (node.children) {
+                node.children.forEach(clean);
+            }
         }
+        tree.forEach(clean);
+        return tree;
     }
-    tree.forEach(clean);
-    return tree;
-}
-
-/** 查询营养产品信息列表 */
-const getList = async () => {
-
-    loading.value = true;
-    const res = await listNutrition(queryParams.value);
-    nutritionList.value = res.rows;
-    total.value = res.total;
-    loading.value = false;
-}
-
-const getDeptList = async () => {
-    loading.value = true;
-    try {
-        const res = await listDept({});
-        if (!res.data) {
-            console.warn("部门数据为空");
-            deptList.value = [];
-            return;
+
+    /** 查询营养产品信息列表 */
+    const getList = async () => {
+
+        loading.value = true;
+        const res = await listNutrition(queryParams.value);
+        nutritionList.value = res.rows;
+        total.value = res.total;
+        loading.value = false;
+    }
+
+    interface ManufacturerOption {
+        value: string | number;
+        label: string;
+    }
+
+    const productManufacturerList = ref < ManufacturerOption[] > ([]);
+
+    const productSupplierList = ref < ManufacturerOption[] > ([]);
+
+    /** 获取生产厂商列表 */
+    const getManufacturerList = async () => {
+        try {
+            const params: ManufacturerQuery = {
+                pageNum: 1,
+                pageSize: 10,
+                name: undefined,
+                params: {}
+            };
+            const res = await listManufacturer(params);
+            productManufacturerList.value = res.rows.map(item => ({
+                value: item.id,
+                label: item.name
+            }));
+        } catch (error) {
+            proxy ?.$modal.msgError("获取生产厂商列表失败");
+            console.error("获取生产厂商列表失败:", error);
         }
+    }
 
-        // 处理树形数据
-        const processedData = proxy ?.handleTree(res.data, 'deptId');
-        if (!processedData) {
-            console.warn("树形数据处理失败");
-            deptList.value = [];
-            return;
+    /** 获取供应商列表 */
+    const getSupplierList = async () => {
+        try {
+            const params: SupplierQuery = {
+                pageNum: 1,
+                pageSize: 10,
+                name: undefined,
+                params: {}
+            };
+            const res = await listSupplier(params);
+            productSupplierList.value = res.rows.map(item => ({
+                value: item.id,
+                label: item.name
+            }));
+        } catch (error) {
+            proxy ?.$modal.msgError("获取供应商列表失败");
+            console.error("获取供应商列表失败:", error);
         }
+    }
 
-        deptList.value = processedData;
+    const getDeptList = async () => {
+        loading.value = true;
+        try {
+            const res = await listDept({
+                pageNum: 1,
+                pageSize: 1000
+            });
+            if (!res.data) {
+                console.warn("部门数据为空");
+                deptList.value = [];
+                return;
+            }
 
-    } catch (error) {
-        console.error('获取部门列表失败:', error);
-        deptList.value = [];
-    } finally {
-        loading.value = false;
+            // 处理树形数据
+            const processedData = proxy ?.handleTree(res.data, 'deptId');
+            if (!processedData) {
+                console.warn("树形数据处理失败");
+                deptList.value = [];
+                return;
+            }
+
+            deptList.value = processedData;
+
+        } catch (error) {
+            console.error('获取部门列表失败:', error);
+            deptList.value = [];
+        } finally {
+            loading.value = false;
+        }
+    };
+
+    /** 下载模板按钮操作 */
+    const downLoadTemplate = () => {
+        proxy ?.getDownload('warehouse/nutrition/downLoadTemplate', {}, `营养产品模版.xlsx`)
     }
-};
-
-/** 下载模板按钮操作 */
-const downLoadTemplate = () => {
-    proxy ?.getDownload('warehouse/nutrition/downLoadTemplate', {}, `营养产品模版.xlsx`)
-}
-
-/** 导入按钮操作 */
-const handleImport = () => {
-    dialogFile.visible = true;
-    fileList.value = [];
-}
-
-// 上传失败
-const handleUploadError = () => {
-    proxy ?.$modal.msgError('上传Excel失败');
-    proxy ?.$modal.closeLoading();
-};
-
-// 上传成功回调
-const handleUploadSuccess = (res: any, file: UploadFile) => {
-    if (res.code === 200) {
-        dialogFile.visible = false;
+
+    /** 导入按钮操作 */
+    const handleImport = () => {
+        dialogFile.visible = true;
         fileList.value = [];
+    }
+
+    // 上传失败
+    const handleUploadError = () => {
+        proxy ?.$modal.msgError('上传Excel失败');
         proxy ?.$modal.closeLoading();
-    } else {
-        proxy ?.$modal.msgError(res.msg);
-        proxy ?.$modal.closeLoading();
+    };
+
+    // 上传成功回调
+    const handleUploadSuccess = (res: any, file: UploadFile) => {
+        if (res.code === 200) {
+            dialogFile.visible = false;
+            fileList.value = [];
+            proxy ?.$modal.closeLoading();
+        } else {
+            proxy ?.$modal.msgError(res.msg);
+            proxy ?.$modal.closeLoading();
+        }
+        fileList.value = [];
+    };
+
+
+    /** 上传前loading加载 */
+    const handleBeforeUpload = (file: any) => {
+        const isLt = file.size / 1024 / 1024 < 10;
+        if (!isLt) {
+            proxy ?.$modal.msgError(`上传头像图片大小不能超过10MB!`);
+            return false;
+        }
+        proxy ?.$modal.loading('正在上传文件,请稍候...');
+        return true;
+    };
+
+    function openBatchSetDialog() {
+        if (!ids.value.length) {
+            proxy ?.$modal.msgWarning('请先选择要批量设置的产品');
+            return;
+        }
+        batchSetForm.shelfLifeReminder = '';
+        batchSetForm.licenseExpiryReminder = '';
+        batchSetDialogVisible.value = true;
     }
-    fileList.value = [];
-};
 
+    async function handleBatchSetSubmit() {
+        const params = {
+            ids: ids.value,
+            shelfLifeReminder: batchSetForm.shelfLifeReminder,
+            licenseExpiryReminder: batchSetForm.licenseExpiryReminder
+        };
 
-/** 上传前loading加载 */
-const handleBeforeUpload = (file: any) => {
-    const isLt = file.size / 1024 / 1024 < 10;
-    if (!isLt) {
-        proxy ?.$modal.msgError(`上传头像图片大小不能超过10MB!`);
-        return false;
+        try {
+            await batchUpdateNutrition(params);
+            proxy ?.$modal.msgSuccess('批量设置成功');
+            batchSetDialogVisible.value = false;
+            getList();
+        } catch (e) {
+            proxy ?.$modal.msgError('批量设置失败');
+        }
     }
-    proxy ?.$modal.loading('正在上传文件,请稍候...');
-    return true;
-};
-
-function openBatchSetDialog() {
-    if (!ids.value.length) {
-        proxy ?.$modal.msgWarning('请先选择要批量设置的产品');
-        return;
+    /** 取消按钮 */
+    const cancel = () => {
+        reset();
+        dialog.visible = false;
+    }
+
+    /** 表单重置 */
+    const reset = () => {
+        form.value = { ...initFormData };
+        nutritionFormRef.value ?.resetFields();
+        fileList.value = [];
     }
-    batchSetForm.shelfLifeReminder = '';
-    batchSetForm.licenseExpiryReminder = '';
-    batchSetDialogVisible.value = true;
-}
-
-async function handleBatchSetSubmit() {
-    const params = {
-        ids: ids.value,
-        shelfLifeReminder: batchSetForm.shelfLifeReminder,
-        licenseExpiryReminder: batchSetForm.licenseExpiryReminder
-    };
 
-    try {
-        await batchUpdateNutrition(params);
-        proxy ?.$modal.msgSuccess('批量设置成功');
-        batchSetDialogVisible.value = false;
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        // 取最后一级分类ID传给后端
+        if (queryParams.value.productCategoryList && queryParams.value.productCategoryList.length) {
+            queryParams.value.productCategory = queryParams.value.productCategoryList.slice(-1)[0];
+        } else {
+            queryParams.value.productCategory = undefined;
+        }
+        queryParams.value.pageNum = 1;
         getList();
-    } catch (e) {
-        proxy ?.$modal.msgError('批量设置失败');
     }
-}
-/** 取消按钮 */
-const cancel = () => {
-    reset();
-    dialog.visible = false;
-}
-
-/** 表单重置 */
-const reset = () => {
-    form.value = { ...initFormData };
-    nutritionFormRef.value ?.resetFields();
-    fileList.value = [];
-}
-
-/** 搜索按钮操作 */
-const handleQuery = () => {
-    // 取最后一级分类ID传给后端
-    if (queryParams.value.productCategoryList && queryParams.value.productCategoryList.length) {
-        queryParams.value.productCategory = queryParams.value.productCategoryList.slice(-1)[0];
-    } else {
+
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        queryFormRef.value ?.resetFields();
+        queryParams.value.productCategoryList = [];
         queryParams.value.productCategory = undefined;
+        queryParams.value.productName = undefined;
+        handleQuery();
+    }
+
+    /** 多选框选中数据 */
+    const handleSelectionChange = (selection: NutritionVO[]) => {
+        ids.value = selection.map(item => item.id);
+        single.value = selection.length != 1;
+        multiple.value = !selection.length;
+    }
+
+    /** 新增按钮操作 */
+    const handleAdd = () => {
+        reset();
+        dialog.visible = true;
+        dialog.title = "添加营养产品信息";
+    }
+
+    /** 修改按钮操作 */
+    const handleUpdate = async (row ? : NutritionVO) => {
+        reset();
+        const _id = row ?.id || ids.value[0]
+        const res = await getNutrition(_id);
+        Object.assign(form.value, res.data);
+        dialog.visible = true;
+        dialog.title = "修改营养产品信息";
     }
-    queryParams.value.pageNum = 1;
-    getList();
-}
-
-/** 重置按钮操作 */
-const resetQuery = () => {
-    queryFormRef.value ?.resetFields();
-    queryParams.value.productCategoryList = [];
-    queryParams.value.productCategory = undefined;
-    queryParams.value.productName = undefined;
-    handleQuery();
-}
-
-/** 多选框选中数据 */
-const handleSelectionChange = (selection: NutritionVO[]) => {
-    ids.value = selection.map(item => item.id);
-    single.value = selection.length != 1;
-    multiple.value = !selection.length;
-}
-
-/** 新增按钮操作 */
-const handleAdd = () => {
-    reset();
-    dialog.visible = true;
-    dialog.title = "添加营养产品信息";
-}
-
-/** 修改按钮操作 */
-const handleUpdate = async (row ? : NutritionVO) => {
-    reset();
-    const _id = row ?.id || ids.value[0]
-    const res = await getNutrition(_id);
-    Object.assign(form.value, res.data);
-    dialog.visible = true;
-    dialog.title = "修改营养产品信息";
-}
-
-/** 提交按钮 */
-const submitForm = () => {
-    nutritionFormRef.value ?.validate(async (valid: boolean) => {
-        if (valid) {
-            buttonLoading.value = true;
-            // form.value.productSpec = form.value.productSpec && form.value.productSpecUnit ? `${form.value.productSpec}${form.value.productSpecUnit}` : '';
-            if (form.value.id) {
-                await updateNutrition(form.value).finally(() => buttonLoading.value = false);
-            } else {
-                await addNutrition(form.value).finally(() => buttonLoading.value = false);
+
+    /** 提交按钮 */
+    const submitForm = () => {
+        nutritionFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                // form.value.productSpec = form.value.productSpec && form.value.productSpecUnit ? `${form.value.productSpec}${form.value.productSpecUnit}` : '';
+                if (form.value.id) {
+                    await updateNutrition(form.value).finally(() => buttonLoading.value = false);
+                } else {
+                    await addNutrition(form.value).finally(() => buttonLoading.value = false);
+                }
+                proxy ?.$modal.msgSuccess("操作成功");
+                dialog.visible = false;
+                await getList();
             }
-            proxy ?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            await getList();
-        }
-    });
-}
-
-/** 保存并上架按钮操作 */
-const submitFormAndPutaway = () => {
-    nutritionFormRef.value ?.validate(async (valid: boolean) => {
-        if (valid) {
-            buttonLoading.value = true;
-            form.value.putFlag = '1';
-            // form.value.productSpec = form.value.productSpec && form.value.productSpecUnit ? `${form.value.productSpec}${form.value.productSpecUnit}` : '';
-            if (form.value.id) {
-                await updateNutrition(form.value).finally(() => buttonLoading.value = false);
-            } else {
-                await addNutrition(form.value).finally(() => buttonLoading.value = false);
+        });
+    }
+
+    /** 保存并上架按钮操作 */
+    const submitFormAndPutaway = () => {
+        nutritionFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                form.value.putFlag = '1';
+                // form.value.productSpec = form.value.productSpec && form.value.productSpecUnit ? `${form.value.productSpec}${form.value.productSpecUnit}` : '';
+                if (form.value.id) {
+                    await updateNutrition(form.value).finally(() => buttonLoading.value = false);
+                } else {
+                    await addNutrition(form.value).finally(() => buttonLoading.value = false);
+                }
+                proxy ?.$modal.msgSuccess("操作成功");
+                dialog.visible = false;
+                await getList();
             }
-            proxy ?.$modal.msgSuccess("操作成功");
-            dialog.visible = false;
-            await getList();
+        });
+    }
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row ? : NutritionVO) => {
+        const _ids = row ?.id || ids.value;
+        await proxy ?.$modal.confirm('是否确认删除营养产品信息编号为"' + _ids + '"的数据项?');
+        await delNutrition(_ids);
+        proxy ?.$modal.msgSuccess("删除成功");
+        await getList();
+    }
+
+    /** 导出按钮操作 */
+    const handleExport = () => {
+        proxy ?.download('warehouse/nutrition/export', {
+            ...queryParams.value
+        }, `nutrition_${new Date().getTime()}.xlsx`)
+    }
+
+
+
+    const onSpecUnitChange = () => {
+        if (!form.value.productSpecUnit) form.value.productSpecUnit = 'g';
+    }
+
+    // 详情弹窗逻辑
+    const handleDetail = async (row: NutritionVO) => {
+        reset();
+        // 确保生产厂商列表已加载
+        if (productManufacturerList.value.length === 0) {
+            await getManufacturerList();
+        }
+         if (productSupplierList.value.length === 0) {
+            await getSupplierList();
         }
+        const res = await getNutrition(row.id);
+        Object.assign(form.value, res.data);
+        detailDialogVisible.value = true;
+        activeTab.value = 'basic';
+    };
+
+    // 上下架切换
+    const handlePutFlag = async (row: NutritionVO, flag: string) => {
+        await proxy ?.$modal.confirm(`是否确认${flag === '1' ? '上架' : '下架'}该产品?`);
+        const updateData = { ...row, putFlag: flag };
+        await updateNutrition(updateData);
+        proxy ?.$modal.msgSuccess(`${flag === '1' ? '上架' : '下架'}成功`);
+        await getList();
+    };
+
+    onMounted(async () => {
+        getList();
+        getDeptList(); // 初始化时加载部门数据
+        getSupplierList(); // 初始化时加载供应商数据
+        getManufacturerList(); // 初始化时加载厂商数据
+        const res = await listCategory();
+        categoryOptions.value = buildCategoryTree(res.rows || []);
+        if (!form.value.productSpecUnit) form.value.productSpecUnit = 'g';
     });
-}
-
-/** 删除按钮操作 */
-const handleDelete = async (row ? : NutritionVO) => {
-    const _ids = row ?.id || ids.value;
-    await proxy ?.$modal.confirm('是否确认删除营养产品信息编号为"' + _ids + '"的数据项?');
-    await delNutrition(_ids);
-    proxy ?.$modal.msgSuccess("删除成功");
-    await getList();
-}
-
-/** 导出按钮操作 */
-const handleExport = () => {
-    proxy ?.download('warehouse/nutrition/export', {
-        ...queryParams.value
-    }, `nutrition_${new Date().getTime()}.xlsx`)
-}
-
-
-
-const onSpecUnitChange = () => {
-    if (!form.value.productSpecUnit) form.value.productSpecUnit = 'g';
-}
-
-// 详情弹窗逻辑
-const handleDetail = async (row: NutritionVO) => {
-    reset();
-    const res = await getNutrition(row.id);
-    Object.assign(form.value, res.data);
-    detailDialogVisible.value = true;
-    activeTab.value = 'basic';
-};
-
-// 上下架切换
-const handlePutFlag = async (row: NutritionVO, flag: string) => {
-    await proxy ?.$modal.confirm(`是否确认${flag === '1' ? '上架' : '下架'}该产品?`);
-    const updateData = { ...row, putFlag: flag };
-    await updateNutrition(updateData);
-    proxy ?.$modal.msgSuccess(`${flag === '1' ? '上架' : '下架'}成功`);
-    await getList();
-};
-
-onMounted(async () => {
-    getList();
-    getDeptList(); // 初始化时加载部门数据
-    const res = await listCategory();
-    categoryOptions.value = buildCategoryTree(res.rows || []);
-    if (!form.value.productSpecUnit) form.value.productSpecUnit = 'g';
-});
-
-const getCategoryName = (categoryIds) => {
-    if (!categoryIds) return '--';
-
-    // 处理多个分类ID的情况
-    const ids = categoryIds.toString().split(',');
-    const categoryNames = ids.map(id => {
-        const findCategory = (categories, targetId) => {
-            for (const category of categories) {
-                if (category.value.toString() === targetId.toString()) {
-                    return category.label;
-                }
-                if (category.children) {
-                    const found = findCategory(category.children, targetId);
-                    if (found) return found;
+
+    const getCategoryName = (categoryIds) => {
+        if (!categoryIds) return '--';
+
+        // 处理多个分类ID的情况
+        const ids = categoryIds.toString().split(',');
+        const categoryNames = ids.map(id => {
+            const findCategory = (categories, targetId) => {
+                for (const category of categories) {
+                    if (category.value.toString() === targetId.toString()) {
+                        return category.label;
+                    }
+                    if (category.children) {
+                        const found = findCategory(category.children, targetId);
+                        if (found) return found;
+                    }
                 }
-            }
-            return null;
-        };
-        return findCategory(categoryOptions.value, id);
-    }).filter(name => name !== null);
-
-    return categoryNames.length > 0 ? categoryNames.join('/') : '--';
-};
-
-// 弹窗回填
-function onLabelConfirm(selectedLabels) {
-    form.value.productLabelList = selectedLabels;
-}
-
-function onContraindicationLabelConfirm(selectedLabels) {
-    form.value.contraindicationLabelList = selectedLabels;
-} // 字典label工具
-function getDictLabel(dictList, value) {
-    if (!dictList || !Array.isArray(dictList)) return value || '--';
-    const found = dictList.find(item => item.value === value);
-    return found ? found.label : value || '--';
-}
+                return null;
+            };
+            return findCategory(categoryOptions.value, id);
+        }).filter(name => name !== null);
+
+        return categoryNames.length > 0 ? categoryNames.join('/') : '--';
+    };
+
+    // 弹窗回填
+    function onLabelConfirm(selectedLabels) {
+        form.value.productLabelList = selectedLabels;
+    }
+
+    function onContraindicationLabelConfirm(selectedLabels) {
+        form.value.contraindicationLabelList = selectedLabels;
+    } // 字典label工具
+    function getDictLabel(dictList, value) {
+        if (!dictList || !Array.isArray(dictList)) return value || '--';
+        const found = dictList.find(item => item.value === value);
+        return found ? found.label : value || '--';
+    }
 </script>
 
 <style lang="scss" scoped>

+ 383 - 0
src/views/warehouse/productManufacturer/index.vue

@@ -0,0 +1,383 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div v-show="showSearch" class="mb-[10px]">
+                <el-card shadow="hover">
+                    <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
+                        <el-form-item label="生产厂商" prop="name">
+                            <el-input v-model="queryParams.name" placeholder="请输入生产厂商" clearable @keyup.enter="handleQuery" />
+                        </el-form-item>
+
+                        <el-form-item>
+                            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                        </el-form-item>
+                    </el-form>
+                </el-card>
+            </div>
+        </transition>
+
+        <el-card shadow="never">
+            <template #header>
+                <el-row :gutter="10" class="mb8">
+                    <el-col :span="1.5">
+                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:manufacturer:add']">新增生产厂商</el-button>
+                    </el-col>
+                    <!-- <el-col :span="1.5">
+                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:manufacturer:edit']">修改</el-button>
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:manufacturer:remove']">删除</el-button>
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:manufacturer:export']">导出</el-button>
+                    </el-col> -->
+                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+                </el-row>
+            </template>
+
+            <el-table v-loading="loading" border :data="manufacturerList" @selection-change="handleSelectionChange">
+                <el-table-column type="selection" width="55" align="center" />
+                <el-table-column label="生产厂商" align="center" prop="name" />
+                <el-table-column label="联系人名称" align="center" prop="contactName" />
+                <el-table-column label="联系人电话" align="center" prop="contactPhone" />
+                <el-table-column label="联系人地址" align="center" prop="address" />
+                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                    <template #default="scope">
+                        <el-tooltip content="编辑" placement="top">
+                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:manufacturer:edit']">编辑</el-button>
+                        </el-tooltip>
+                        <el-tooltip content="详情" placement="top">
+                            <el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['system:manufacturer:query']">详情</el-button>
+                        </el-tooltip>
+                        <el-tooltip content="删除" placement="top">
+                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:manufacturer:remove']">删除</el-button>
+                        </el-tooltip>
+                    </template>
+                </el-table-column>
+            </el-table>
+
+            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+
+        <!-- 添加或修改生产厂商对话框 -->
+        <el-dialog :title="dialog.title" v-model="dialog.visible" width="38%" append-to-body>
+            <el-form ref="manufacturerFormRef" :model="form" :rules="rules" label-width="130px">
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="生产厂商" prop="name">
+                            <el-input v-model="form.name" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="联系人" prop="contactName">
+                            <el-input v-model="form.contactName" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="联系电话" prop="contactPhone">
+                            <el-input v-model="form.contactPhone" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="联系地址" prop="address">
+                            <el-input v-model="form.address" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-form-item label="描述" prop="description">
+                    <el-input type="textarea" :rows="3" v-model="form.description" placeholder="请输入" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">保 存</el-button>
+                    <el-button @click="cancel">关 闭</el-button>
+                </div>
+            </template>
+        </el-dialog>
+
+        <!-- 详情对话框 -->
+        <el-dialog title="详情" v-model="detailDialog.visible" width="38%" :close-on-click-modal="false" append-to-body>
+            <div class="detail-container">
+                <div class="detail-row">
+                    <div class="detail-label">生产厂商名称</div>
+                    <div class="detail-content">{{ detailForm.name }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">联系人</div>
+                    <div class="detail-content">{{ detailForm.contactName }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">联系电话</div>
+                    <div class="detail-content">{{ detailForm.contactPhone }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">联系地址</div>
+                    <div class="detail-content">{{ detailForm.address }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">描述</div>
+                    <div class="detail-content">{{ detailForm.description }}</div>
+                </div>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button @click="detailDialog.visible = false">关闭</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="ProductManufacturer" lang="ts">
+    import { listManufacturer, getManufacturer, delManufacturer, addManufacturer, updateManufacturer } from '@/api/warehouse/productManufacturer';
+    import { ManufacturerVO, ManufacturerQuery, ManufacturerForm } from '@/api/warehouse/productManufacturer/types';
+    import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs, onMounted } from 'vue';
+    import type { FormInstance } from 'element-plus';
+
+    interface DialogOption {
+        visible: boolean;
+        title ? : string;
+    }
+
+    interface PageData < T, Q > {
+        form: T;
+        queryParams: {
+            pageNum: number;
+            pageSize: number;
+            params: Record < string,
+            any > ;
+        } & Q;
+        rules ? : Record < string,
+        any[] > ;
+    }
+
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+    const manufacturerList = ref < ManufacturerVO[] > ([]);
+    const buttonLoading = ref(false);
+    const loading = ref(true);
+    const showSearch = ref(true);
+    const ids = ref < Array < string | number >> ([]);
+    const single = ref(true);
+    const multiple = ref(true);
+    const total = ref(0);
+
+    const queryFormRef = ref < FormInstance > ();
+    const manufacturerFormRef = ref < FormInstance > ();
+
+    const dialog = reactive < DialogOption > ({
+        visible: false,
+        title: ''
+    });
+
+    const detailDialog = reactive < DialogOption > ({
+        visible: false
+    });
+
+    const detailForm = reactive < ManufacturerForm > ({
+        id: undefined,
+        name: undefined,
+        contactName: undefined,
+        contactPhone: undefined,
+        address: undefined,
+        description: undefined
+    });
+
+    const initFormData: ManufacturerForm = {
+        id: undefined,
+        name: undefined,
+        contactName: undefined,
+        contactPhone: undefined,
+        address: undefined,
+        description: undefined,
+    }
+    const data = reactive < PageData < ManufacturerForm,
+        ManufacturerQuery >> ({
+            form: { ...initFormData },
+            queryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                name: undefined,
+                params: {}
+            },
+            rules: {
+
+                name: [
+                    { required: true, message: "生产厂商不能为空", trigger: "blur" }
+                ],
+            }
+        });
+
+    const { queryParams, form, rules } = toRefs(data);
+
+    /** 查询生产厂商列表 */
+    const getList = async () => {
+        loading.value = true;
+        const res = await listManufacturer(queryParams.value);
+        manufacturerList.value = res.rows;
+        total.value = res.total;
+        loading.value = false;
+    }
+
+    /** 取消按钮 */
+    const cancel = () => {
+        reset();
+        dialog.visible = false;
+    }
+
+    /** 表单重置 */
+    const reset = () => {
+        form.value = { ...initFormData };
+        manufacturerFormRef.value ?.resetFields();
+    }
+
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        queryParams.value.pageNum = 1;
+        getList();
+    }
+
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        queryFormRef.value ?.resetFields();
+        handleQuery();
+    }
+
+    /** 多选框选中数据 */
+    const handleSelectionChange = (selection: ManufacturerVO[]) => {
+        ids.value = selection.map(item => item.id);
+        single.value = selection.length != 1;
+        multiple.value = !selection.length;
+    }
+
+    /** 新增按钮操作 */
+    const handleAdd = () => {
+        reset();
+        dialog.visible = true;
+        dialog.title = "新增";
+    }
+
+    /** 修改按钮操作 */
+    const handleUpdate = async (row ? : ManufacturerVO) => {
+        reset();
+        const _id = row ?.id || ids.value[0]
+        const res = await getManufacturer(_id);
+        Object.assign(form.value, res.data);
+        dialog.visible = true;
+        dialog.title = "编辑";
+    }
+    const handleDetail = async (row: ManufacturerVO) => {
+        try {
+            const res = await getManufacturer(row.id);
+            Object.assign(detailForm, res.data);
+            detailDialog.visible = true;
+        } catch (error) {
+            proxy ?.$modal.msgError("获取详情失败");
+        }
+    };
+
+    /** 提交按钮 */
+    const submitForm = () => {
+        manufacturerFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                if (form.value.id) {
+                    await updateManufacturer(form.value).finally(() => buttonLoading.value = false);
+                } else {
+                    await addManufacturer(form.value).finally(() => buttonLoading.value = false);
+                }
+                proxy ?.$modal.msgSuccess("操作成功");
+                dialog.visible = false;
+                await getList();
+            }
+        });
+    }
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row ? : ManufacturerVO) => {
+        const _ids = row ?.id || ids.value;
+        await proxy ?.$modal.confirm('是否确认删除生产厂商编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+        await delManufacturer(_ids);
+        proxy ?.$modal.msgSuccess("删除成功");
+        await getList();
+    }
+
+    /** 导出按钮操作 */
+    const handleExport = () => {
+        proxy ?.download('warehouse/productManufacturer/export', {
+            ...queryParams.value
+        }, `manufacturer_${new Date().getTime()}.xlsx`)
+    }
+
+    onMounted(() => {
+        getList();
+    });
+</script>
+
+<style scoped>
+    .dialog-footer {
+        text-align: center;
+        padding: 10px 0;
+    }
+
+    :deep(.el-dialog) {
+        border-radius: 4px;
+    }
+
+    :deep(.el-dialog__header) {
+        margin: 0;
+        padding: 12px 20px;
+        border-bottom: 1px solid #dcdfe6;
+        background-color: #f5f7fa;
+    }
+
+    :deep(.el-dialog__title) {
+        font-size: 14px;
+        font-weight: 500;
+    }
+
+    :deep(.el-dialog__headerbtn) {
+        top: 14px;
+    }
+
+    :deep(.el-dialog__body) {
+        padding: 0;
+    }
+
+    .detail-container {
+        background: #fff;
+    }
+
+    .detail-row {
+        display: flex;
+        border-bottom: 1px solid #dcdfe6;
+    }
+
+    .detail-row:last-child {
+        border-bottom: none;
+    }
+
+    .detail-label {
+        width: 50%;
+        padding: 12px 20px;
+        background: #f5f7fa;
+        border-right: 1px solid #dcdfe6;
+        box-sizing: border-box;
+    }
+
+    .detail-content {
+        width: 50%;
+        padding: 12px 20px;
+        box-sizing: border-box;
+    }
+
+    :deep(.el-dialog__footer) {
+        margin: 0;
+        border-top: 1px solid #dcdfe6;
+        padding: 12px 20px;
+    }
+</style>

+ 371 - 0
src/views/warehouse/productSupplier/index.vue

@@ -0,0 +1,371 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div v-show="showSearch" class="mb-[10px]">
+                <el-card shadow="hover">
+                    <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="120px">
+                        <el-form-item label="供应商" prop="name">
+                            <el-input v-model="queryParams.name" placeholder="请输入供应商" clearable @keyup.enter="handleQuery" />
+                        </el-form-item>
+
+                        <el-form-item>
+                            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                        </el-form-item>
+                    </el-form>
+                </el-card>
+            </div>
+        </transition>
+
+        <el-card shadow="never">
+            <template #header>
+                <el-row :gutter="10" class="mb8">
+                    <el-col :span="1.5">
+                        <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:supplier:add']">新增供应商</el-button>
+                    </el-col>
+                    <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+                </el-row>
+            </template>
+
+            <el-table v-loading="loading" border :data="supplierList" @selection-change="handleSelectionChange">
+                <el-table-column type="selection" width="55" align="center" />
+                <el-table-column label="供应商" align="center" prop="name" />
+                <el-table-column label="联系人名称" align="center" prop="contactName" />
+                <el-table-column label="联系人电话" align="center" prop="contactPhone" />
+                <el-table-column label="联系人地址" align="center" prop="address" />
+                <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+                    <template #default="scope">
+                        <el-tooltip content="编辑" placement="top">
+                            <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:supplier:edit']">编辑</el-button>
+                        </el-tooltip>
+                        <el-tooltip content="详情" placement="top">
+                            <el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['system:supplier:query']">详情</el-button>
+                        </el-tooltip>
+                        <el-tooltip content="删除" placement="top">
+                            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:supplier:remove']">删除</el-button>
+                        </el-tooltip>
+                    </template>
+                </el-table-column>
+            </el-table>
+
+            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </el-card>
+
+        <!-- 添加或修改供应商对话框 -->
+        <el-dialog :title="dialog.title" v-model="dialog.visible" width="38%" append-to-body>
+            <el-form ref="supplierFormRef" :model="form" :rules="rules" label-width="130px">
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="供应商" prop="name">
+                            <el-input v-model="form.name" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="联系人" prop="contactName">
+                            <el-input v-model="form.contactName" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="20">
+                    <el-col :span="12">
+                        <el-form-item label="联系电话" prop="contactPhone">
+                            <el-input v-model="form.contactPhone" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="联系地址" prop="address">
+                            <el-input v-model="form.address" placeholder="请输入" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-form-item label="描述" prop="description">
+                    <el-input type="textarea" :rows="3" v-model="form.description" placeholder="请输入" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">保 存</el-button>
+                    <el-button @click="cancel">关 闭</el-button>
+                </div>
+            </template>
+        </el-dialog>
+
+        <!-- 详情对话框 -->
+        <el-dialog title="详情" v-model="detailDialog.visible" width="38%" :close-on-click-modal="false" append-to-body>
+            <div class="detail-container">
+                <div class="detail-row">
+                    <div class="detail-label">供应商名称</div>
+                    <div class="detail-content">{{ detailForm.name }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">联系人</div>
+                    <div class="detail-content">{{ detailForm.contactName }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">联系电话</div>
+                    <div class="detail-content">{{ detailForm.contactPhone }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">联系地址</div>
+                    <div class="detail-content">{{ detailForm.address }}</div>
+                </div>
+                <div class="detail-row">
+                    <div class="detail-label">描述</div>
+                    <div class="detail-content">{{ detailForm.description }}</div>
+                </div>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button @click="detailDialog.visible = false">关闭</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="ProductSupplier" lang="ts">
+    import { listSupplier, getSupplier, delSupplier, addSupplier, updateSupplier } from '@/api/warehouse/productSupplier';
+    import { SupplierVO, SupplierQuery, SupplierForm } from '@/api/warehouse/productSupplier/types';
+    import { ComponentInternalInstance, getCurrentInstance, ref, reactive, toRefs, onMounted } from 'vue';
+    import type { FormInstance } from 'element-plus';
+
+    interface DialogOption {
+        visible: boolean;
+        title?: string;
+    }
+
+    interface PageData<T, Q> {
+        form: T;
+        queryParams: {
+            pageNum: number;
+            pageSize: number;
+            params: Record<string, any>;
+        } & Q;
+        rules?: Record<string, any[]>;
+    }
+
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+    const supplierList = ref<SupplierVO[]>([]);
+    const buttonLoading = ref(false);
+    const loading = ref(true);
+    const showSearch = ref(true);
+    const ids = ref<Array<string | number>>([]);
+    const single = ref(true);
+    const multiple = ref(true);
+    const total = ref(0);
+
+    const queryFormRef = ref<FormInstance>();
+    const supplierFormRef = ref<FormInstance>();
+
+    const dialog = reactive<DialogOption>({
+        visible: false,
+        title: ''
+    });
+
+    const detailDialog = reactive<DialogOption>({
+        visible: false
+    });
+
+    const detailForm = reactive<SupplierForm>({
+        id: undefined,
+        name: undefined,
+        contactName: undefined,
+        contactPhone: undefined,
+        address: undefined,
+        description: undefined
+    });
+
+    const initFormData: SupplierForm = {
+        id: undefined,
+        name: undefined,
+        contactName: undefined,
+        contactPhone: undefined,
+        address: undefined,
+        description: undefined,
+    }
+    const data = reactive<PageData<SupplierForm, SupplierQuery>>({
+        form: { ...initFormData },
+        queryParams: {
+            pageNum: 1,
+            pageSize: 10,
+            name: undefined,
+            params: {}
+        },
+        rules: {
+            name: [
+                { required: true, message: "供应商不能为空", trigger: "blur" }
+            ],
+        }
+    });
+
+    const { queryParams, form, rules } = toRefs(data);
+
+    /** 查询供应商列表 */
+    const getList = async () => {
+        loading.value = true;
+        const res = await listSupplier(queryParams.value);
+        supplierList.value = res.rows;
+        total.value = res.total;
+        loading.value = false;
+    }
+
+    /** 取消按钮 */
+    const cancel = () => {
+        reset();
+        dialog.visible = false;
+    }
+
+    /** 表单重置 */
+    const reset = () => {
+        form.value = { ...initFormData };
+        supplierFormRef.value?.resetFields();
+    }
+
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        queryParams.value.pageNum = 1;
+        getList();
+    }
+
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        queryFormRef.value?.resetFields();
+        handleQuery();
+    }
+
+    /** 多选框选中数据 */
+    const handleSelectionChange = (selection: SupplierVO[]) => {
+        ids.value = selection.map(item => item.id);
+        single.value = selection.length != 1;
+        multiple.value = !selection.length;
+    }
+
+    /** 新增按钮操作 */
+    const handleAdd = () => {
+        reset();
+        dialog.visible = true;
+        dialog.title = "新增";
+    }
+
+    /** 修改按钮操作 */
+    const handleUpdate = async (row?: SupplierVO) => {
+        reset();
+        const _id = row?.id || ids.value[0]
+        const res = await getSupplier(_id);
+        Object.assign(form.value, res.data);
+        dialog.visible = true;
+        dialog.title = "编辑";
+    }
+
+    const handleDetail = async (row: SupplierVO) => {
+        try {
+            const res = await getSupplier(row.id);
+            Object.assign(detailForm, res.data);
+            detailDialog.visible = true;
+        } catch (error) {
+            proxy?.$modal.msgError("获取详情失败");
+        }
+    };
+
+    /** 提交按钮 */
+    const submitForm = () => {
+        supplierFormRef.value?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                if (form.value.id) {
+                    await updateSupplier(form.value).finally(() => buttonLoading.value = false);
+                } else {
+                    await addSupplier(form.value).finally(() => buttonLoading.value = false);
+                }
+                proxy?.$modal.msgSuccess("操作成功");
+                dialog.visible = false;
+                await getList();
+            }
+        });
+    }
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row?: SupplierVO) => {
+        const _ids = row?.id || ids.value;
+        await proxy?.$modal.confirm('是否确认删除供应商编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+        await delSupplier(_ids);
+        proxy?.$modal.msgSuccess("删除成功");
+        await getList();
+    }
+
+    /** 导出按钮操作 */
+    const handleExport = () => {
+        proxy?.download('warehouse/productSupplier/export', {
+            ...queryParams.value
+        }, `supplier_${new Date().getTime()}.xlsx`)
+    }
+
+    onMounted(() => {
+        getList();
+    });
+</script>
+
+<style scoped>
+    .dialog-footer {
+        text-align: center;
+        padding: 10px 0;
+    }
+
+    :deep(.el-dialog) {
+        border-radius: 4px;
+    }
+
+    :deep(.el-dialog__header) {
+        margin: 0;
+        padding: 12px 20px;
+        border-bottom: 1px solid #dcdfe6;
+        background-color: #f5f7fa;
+    }
+
+    :deep(.el-dialog__title) {
+        font-size: 14px;
+        font-weight: 500;
+    }
+
+    :deep(.el-dialog__headerbtn) {
+        top: 14px;
+    }
+
+    :deep(.el-dialog__body) {
+        padding: 0;
+    }
+
+    .detail-container {
+        background: #fff;
+    }
+
+    .detail-row {
+        display: flex;
+        border-bottom: 1px solid #dcdfe6;
+    }
+
+    .detail-row:last-child {
+        border-bottom: none;
+    }
+
+    .detail-label {
+        width: 50%;
+        padding: 12px 20px;
+        background: #f5f7fa;
+        border-right: 1px solid #dcdfe6;
+        box-sizing: border-box;
+    }
+
+    .detail-content {
+        width: 50%;
+        padding: 12px 20px;
+        box-sizing: border-box;
+    }
+
+    :deep(.el-dialog__footer) {
+        margin: 0;
+        border-top: 1px solid #dcdfe6;
+        padding: 12px 20px;
+    }
+</style>

+ 6 - 3
src/views/warehouse/suppliesManage/addOrEditForm.vue

@@ -59,7 +59,7 @@
                 <el-col :span="12">
                     <el-form-item label="生产厂商:" prop="manufacturer">
                         <el-select v-model="form.manufacturer" placeholder="请选择" clearable>
-                            <el-option v-for="dict in product_manufacturer" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            <el-option v-for="item in productManufacturerList" :key="item.value" :label="item.label" :value="item.value" />
                         </el-select>
                     </el-form-item>
                 </el-col>
@@ -77,7 +77,7 @@
                 <el-col :span="12">
                     <el-form-item label="供应商:" prop="supplier">
                         <el-select v-model="form.supplier" placeholder="请选择" clearable>
-                            <el-option v-for="dict in product_supplier" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            <el-option v-for="item in productSupplierList" :key="item.value" :label="item.label" :value="item.value" />
                         </el-select>
                     </el-form-item>
                 </el-col>
@@ -195,7 +195,7 @@
     import LabelDialog from '@/views/warehouse/nutriProduct/labelDialog.vue';
 
     const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-    const { product_qualification, product_package_unit, product_supplier, put_flag, product_manufacturer, product_spec_unit } = toRefs < any > (proxy ?.useDict('product_qualification', 'product_package_unit', 'product_supplier', 'put_flag', 'product_manufacturer', 'product_spec_unit'));
+    const { product_qualification, product_package_unit, put_flag, product_spec_unit } = toRefs < any > (proxy ?.useDict('product_qualification', 'product_package_unit', 'put_flag', 'product_spec_unit'));
 
     const loading = ref(true);
     const router = useRouter();
@@ -211,6 +211,9 @@
     const unit_options = ref < any[] > ([{ label: '个', value: '1' }]); // TODO: 替换为实际数据
 
 
+    const productSupplierList = ref(JSON.parse(route.query.productSupplierList as string || '[]'));
+    const productManufacturerList = ref(JSON.parse(route.query.productManufacturerList as string || '[]'));
+
     const rules = {
         suppliesName: [{ required: true, message: '耗材名称不能为空', trigger: 'blur' }],
         hospitalSystemCode: [{ required: true, message: "院方系统编码不能为空", trigger: "blur" }],

+ 5 - 8
src/views/warehouse/suppliesManage/detailForm.vue

@@ -11,8 +11,8 @@
                     <div><b><span style="color:red;margin-right: 3px">*</span>耗材名称:</b>{{ formData.suppliesName || '--' }}</div>
                     <div><b><span style="color:red;margin-right: 3px">*</span>商品编码:</b>{{ formData.suppliesCode || '--' }}</div>
                     <div><b><span style="color:red;margin-right: 3px">*</span>院方系统编码:</b>{{ formData.hospitalSystemCode || '--' }}</div>
-                    <div><b>生产厂商:</b>{{ getDictLabel(product_manufacturer, formData.manufacturer) || '--' }}</div>
-                    <div><b>供应商:</b>{{ getDictLabel(product_supplier, formData.supplier) || '--' }}</div>
+                    <div><b>生产厂商:</b>{{ productManufacturerList.find(item => item.value === formData.manufacturer)?.label|| '--' }}</div>
+                    <div><b>供应商:</b>{{ productSupplierList.find(item => item.value === formData.supplier)?.label || '--' }}</div>
                     <div class="long-label"><b>许可证有效期提醒:</b>{{ formData.licenseExpiryReminder ? formData.licenseExpiryReminder + '个月' : '--' }}</div>
                     <div class="long-label"><b>商品许可证有效期至:</b>{{ formData.productLicenseExpiry ? formData.productLicenseExpiry.slice(0, 10) : '--' }}</div>
                     <div><b><span style="color:red;margin-right: 3px">*</span>保质期:</b>{{ formData.shelfLife ? formData.shelfLife + '个月' : '--' }}</div>
@@ -58,11 +58,12 @@
         throw new Error('getCurrentInstance() returned null');
     }
 
+    const productSupplierList = ref(JSON.parse(route.query.productSupplierList as string || '[]'));
+    const productManufacturerList = ref(JSON.parse(route.query.productManufacturerList as string || '[]'));
+
     // 字典数据
     const product_qualification = ref([]);
     const product_package_unit = ref([]);
-    const product_supplier = ref([]);
-    const product_manufacturer = ref([]);
     const product_spec_unit = ref([]);
 
     // 加载字典数据
@@ -70,14 +71,10 @@
         const dictData = await proxy.useDict(
             'product_qualification',
             'product_package_unit',
-            'product_supplier',
-            'product_manufacturer',
             'product_spec_unit'
         );
         product_qualification.value = dictData.product_qualification;
         product_package_unit.value = dictData.product_package_unit;
-        product_supplier.value = dictData.product_supplier;
-        product_manufacturer.value = dictData.product_manufacturer;
         product_spec_unit.value = dictData.product_spec_unit;
     };
 

+ 70 - 2
src/views/warehouse/suppliesManage/index.vue

@@ -132,6 +132,12 @@
     import { globalHeaders } from '@/utils/request';
     import type { FormInstance } from 'element-plus';
 
+    import { listSupplier } from '@/api/warehouse/productSupplier'
+    import { listManufacturer } from '@/api/warehouse/productManufacturer'
+
+    import type { SupplierQuery } from '@/api/warehouse/productSupplier/types';
+    import type { ManufacturerQuery } from '@/api/warehouse/productManufacturer/types';
+
     const router = useRouter();
     const { proxy } = getCurrentInstance() as ComponentInternalInstance;
     const { product_package_unit, put_flag, product_spec_unit } = toRefs < any > (proxy ?.useDict('product_package_unit', 'put_flag', 'product_spec_unit'));
@@ -159,12 +165,20 @@
 
     };
 
+    interface ManufacturerOption {
+        value: string | number;
+        label: string;
+    }
 
     // 分类选项
     const categoryOptions = ref < any[] > ([]);
 
     const queryFormRef = ref < FormInstance > ();
 
+    const productSupplierList = ref < ManufacturerOption[] > ([]);
+
+    const productManufacturerList = ref < ManufacturerOption[] > ([]);
+
     const queryParams = reactive < SuppliesManageQuery > ({
         pageNum: 1,
         pageSize: 10,
@@ -202,6 +216,8 @@
 
     onMounted(async () => {
         getList();
+        getSupplierList(); // 初始化时加载供应商数据
+        getManufacturerList(); // 初始化时加载厂商数据
         const res = await listSuppliesCategory();
         categoryOptions.value = buildCategoryTree(res.rows || []);
     });
@@ -238,10 +254,56 @@
         queryParams.suppliesName = undefined;
         handleQuery();
     };
+    /** 获取生产厂商列表 */
+    const getManufacturerList = async () => {
+        try {
+            const params: ManufacturerQuery = {
+                pageNum: 1,
+                pageSize: 10,
+                name: undefined,
+                params: {}
+            };
+            const res = await listManufacturer(params);
+            productManufacturerList.value = res.rows.map(item => ({
+                value: item.id,
+                label: item.name
+            }));
+        } catch (error) {
+            proxy ?.$modal.msgError("获取生产厂商列表失败");
+            console.error("获取生产厂商列表失败:", error);
+        }
+    }
+
+    /** 获取供应商列表 */
+    const getSupplierList = async () => {
+        try {
+            const params: SupplierQuery = {
+                pageNum: 1,
+                pageSize: 10,
+                name: undefined,
+                params: {}
+            };
+            const res = await listSupplier(params);
+            productSupplierList.value = res.rows.map(item => ({
+                value: item.id,
+                label: item.name
+            }));
+        } catch (error) {
+            proxy ?.$modal.msgError("获取供应商列表失败");
+            console.error("获取供应商列表失败:", error);
+        }
+    }
+
 
     /** 新增按钮操作 */
     const handleAdd = () => {
-        router.push('/warehouse/suppliesAddOrEdit');
+        router.push({
+            path: '/warehouse/suppliesAddOrEdit',
+            query: {
+                productSupplierList: JSON.stringify(productSupplierList.value), // 序列化数组数据
+                productManufacturerList: JSON.stringify(productManufacturerList.value), // 序列化数组数据
+            },
+        });
     };
 
     /** 导入按钮操作 */
@@ -359,7 +421,13 @@
 
     /** 查看详情 */
     const handleDetail = (row: SuppliesManageVO) => {
-        router.push(`/warehouse/suppliesManageDetail/${row.id}`);
+        router.push({
+            path: `/warehouse/suppliesManageDetail/${row.id}`,
+            query: {
+                productSupplierList: JSON.stringify(productSupplierList.value), // 序列化数组数据
+                productManufacturerList: JSON.stringify(productManufacturerList.value), // 序列化数组数据
+            },
+        });
     };
 
     /** 多选框选中数据 */