HuRongxin 3 mesiacov pred
rodič
commit
5afd1f40f8

+ 1 - 0
package.json

@@ -70,6 +70,7 @@
     "typescript": "~5.8.3",
     "unocss": "66.0.0",
     "unplugin-auto-import": "19.1.2",
+    "unplugin-element-plus": "^0.10.0",
     "unplugin-icons": "22.1.0",
     "unplugin-vue-components": "28.5.0",
     "unplugin-vue-setup-extend-plus": "1.0.1",

+ 18 - 0
product.txt

@@ -0,0 +1,18 @@
++------------------------------------------------------------------+
+|                        产品分类管理                                  |
++------------------------------------------------------------------+
+|                                                                    |
+| 分类名称: [____________]  [查询]  [重置]                            |
+|                                                                    |
++------------------------------------------------------------------+
+|                                                                    |
+| [新增]  [关闭所有]                                                 |
+|                                                                    |
+| +--------------------------------------------------------------+ |
+| |  分类名称    |    操作                                         | |
+| |--------------------------------------------------------------|  |
+| |  肠内营养    |    [编辑] [删除]                               | |
+| |  产品        |    [编辑] [删除]                               | |
+| +--------------------------------------------------------------+ |
+|                                                                    |
++------------------------------------------------------------------+ 

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/warehouse/productCategory/types'
+
+/**
+ * 查询产品分类列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
+  return request({
+    url: '/warehouse/productCategory/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询产品分类详细
+ * @param categoryId
+ */
+export const getCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
+  return request({
+    url: '/warehouse/productCategory/' + categoryId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增产品分类
+ * @param data
+ */
+export const addCategory = (data: CategoryForm) => {
+  return request({
+    url: '/warehouse/productCategory',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改产品分类
+ * @param data
+ */
+export const updateCategory = (data: CategoryForm) => {
+  return request({
+    url: '/warehouse/productCategory',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除产品分类
+ * @param categoryId
+ */
+export const delCategory = (categoryId: string | number | Array<string | number>) => {
+  return request({
+    url: '/warehouse/productCategory/' + categoryId,
+    method: 'delete'
+  });
+};

+ 71 - 0
src/api/warehouse/productCategory/types.ts

@@ -0,0 +1,71 @@
+export interface CategoryVO {
+  /**
+   * 产品分类ID
+   */
+  categoryId: string | number;
+
+  /**
+   * 父产品分类id
+   */
+  parentId: string | number;
+
+  /**
+   * 产品分类名称
+   */
+  categoryName: string;
+
+  /**
+   * 显示顺序
+   */
+  orderNum: number;
+
+}
+
+export interface CategoryForm extends BaseEntity {
+  /**
+   * 产品分类ID
+   */
+  categoryId?: string | number;
+
+  /**
+   * 父产品分类id
+   */
+  parentId?: string | number;
+
+  /**
+   * 产品分类名称
+   */
+  categoryName?: string;
+
+  /**
+   * 显示顺序
+   */
+  orderNum?: number;
+
+}
+
+export interface CategoryQuery extends PageQuery {
+
+  /**
+   * 父产品分类id
+   */
+  parentId?: string | number;
+
+  /**
+   * 产品分类名称
+   */
+  categoryName?: string;
+
+  /**
+   * 显示顺序
+   */
+  orderNum?: number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { NutritionVO, NutritionForm, NutritionQuery } from '@/api/warehouse/productNutrition/types';
+
+/**
+ * 查询营养产品信息列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listNutrition = (query?: NutritionQuery): AxiosPromise<NutritionVO[]> => {
+  return request({
+    url: '/warehouse/nutrition/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询营养产品信息详细
+ * @param id
+ */
+export const getNutrition = (id: string | number): AxiosPromise<NutritionVO> => {
+  return request({
+    url: '/warehouse/nutrition/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增营养产品信息
+ * @param data
+ */
+export const addNutrition = (data: NutritionForm) => {
+  return request({
+    url: '/warehouse/nutrition',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改营养产品信息
+ * @param data
+ */
+export const updateNutrition = (data: NutritionForm) => {
+  return request({
+    url: '/warehouse/nutrition',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除营养产品信息
+ * @param id
+ */
+export const delNutrition = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/warehouse/nutrition/' + id,
+    method: 'delete'
+  });
+};

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

@@ -0,0 +1,1692 @@
+export interface NutritionVO {
+    /**
+     * 主键ID
+     */
+    id: string | number;
+
+    /**
+     * 产品名称
+     */
+    productName: string;
+
+    /**
+     * 院方系统编码
+     */
+    hospitalSystemCode: string;
+
+    /**
+     * 商品编码
+     */
+    productCode: string;
+
+    /**
+     * 产品所属分类
+     */
+    productCategory: string;
+
+    productCategoryList?: string[];
+
+    /**
+     * 生产厂商
+     */
+    manufacturer: string;
+
+    /**
+     * 品牌
+     */
+    brand: string;
+
+    /**
+     * 产品所属标签
+     */
+    productLabel: string;
+
+    /**
+     * 许可证有效期提醒
+     */
+    licenseExpiryReminder: string;
+
+    /**
+     * 商品许可证有效期至
+     */
+    productLicenseExpiry: string;
+
+    /**
+     * 商品资质
+     */
+    productQualification: string;
+
+    /**
+     * 批准文号
+     */
+    approvalNumber: string;
+
+    /**
+     * 口味
+     */
+    taste: string;
+
+    /**
+     * 剂型/形态
+     */
+    dosageForm: string;
+
+    /**
+     * 供应商
+     */
+    supplier: string;
+
+    /**
+     * 产品适用科室
+     */
+    applicableDepartment: string;
+
+    /**
+     * 禁忌症所属标签
+     */
+    contraindicationLabel: string;
+
+    /**
+     * 保质期临期提醒
+     */
+    shelfLifeReminder: string;
+
+    /**
+     * 保质期
+     */
+    shelfLife: string;
+
+    /**
+     * 入货价格
+     */
+    purchasePrice: number;
+
+    /**
+     * 入货单位
+     */
+    purchaseUnit: string;
+
+    /**
+     * 默认用法
+     */
+    defaultUsage: string;
+
+    /**
+     * 预包装单位
+     */
+    packageUnit: string;
+
+    /**
+     * 商品规格
+     */
+    productSpec: string;
+
+    /**
+     * 预包装销售价
+     */
+    packagePrice: number;
+
+    /**
+     * 最小包装单位
+     */
+    minUnit: string;
+
+    /**
+     * 最小包装规格
+     */
+    minSpec: string;
+
+    /**
+     * 净含量/规格
+     */
+    netContent: string;
+
+    /**
+     * 配置销售价格
+     */
+    configSalePrice: number;
+
+    /**
+     * 配置损耗率
+     */
+    configLossRate: number;
+
+    /**
+     * 热量
+     */
+    calorie: number;
+
+    /**
+     * 碳水化合物
+     */
+    carbohydrate: number;
+
+    /**
+     * 热能
+     */
+    heatEnergy: number;
+
+    /**
+     * 蛋白质
+     */
+    protein: number;
+
+    /**
+     * 脂肪
+     */
+    fat: number;
+
+    /**
+     * 钙
+     */
+    ca: number;
+
+    /**
+     * 磷
+     */
+    p: number;
+
+    /**
+     * 钾
+     */
+    k: number;
+
+    /**
+     * 钠
+     */
+    na: number;
+
+    /**
+     * 镁
+     */
+    mg: number;
+
+    /**
+     * 氯
+     */
+    cl: number;
+
+    /**
+     * 铁
+     */
+    fe: number;
+
+    /**
+     * 锌
+     */
+    zn: number;
+
+    /**
+     * 硒
+     */
+    se: number;
+
+    /**
+     * 铜
+     */
+    cu: number;
+
+    /**
+     * 锰
+     */
+    mn: number;
+
+    /**
+     * 碘
+     */
+    i: number;
+
+    /**
+     * 氟
+     */
+    f: number;
+
+    /**
+     * 铬
+     */
+    cr: number;
+
+    /**
+     * 钼
+     */
+    mo: number;
+
+    /**
+     * 异亮氨酸
+     */
+    isoleucine: number;
+
+    /**
+     * 色氨酸
+     */
+    tryptophan: number;
+
+    /**
+     * 含硫氨基酸
+     */
+    sulfurAminoAcid: string | number;
+
+    /**
+     * 组氨酸
+     */
+    histidine: string | number;
+
+    /**
+     * 芳香族氨基酸
+     */
+    aromaticAminoAcid: string | number;
+
+    /**
+     * 谷氨酸
+     */
+    glutamicAcid: string | number;
+
+    /**
+     * 苏氨酸
+     */
+    threonine: number;
+
+    /**
+     * 丝氨酸
+     */
+    serine: number;
+
+    /**
+     * 精氨酸
+     */
+    arginine: number;
+
+    /**
+     * 赖氨酸
+     */
+    lysine: number;
+
+    /**
+     * 天冬氨酸
+     */
+    asparticAcid: string | number;
+
+    /**
+     * 胱氨酸
+     */
+    cysteine: number;
+
+    /**
+     * 脯氨酸
+     */
+    proline: number;
+
+    /**
+     * 酪氨酸
+     */
+    tyrosine: number;
+
+    /**
+     * 亮氨酸
+     */
+    leucine: number;
+
+    /**
+     * 缬氨酸
+     */
+    valine: number;
+
+    /**
+     * 蛋氨酸
+     */
+    methionine: number;
+
+    /**
+     * 丙氨酸
+     */
+    alanine: number;
+
+    /**
+     * 苯丙氨酸
+     */
+    phenylalanine: number;
+
+    /**
+     * 甘氨酸
+     */
+    glycine: number;
+
+    /**
+     * 脂肪酸
+     */
+    fattyAcid: string | number;
+
+    /**
+     * 饱和脂肪酸
+     */
+    saturatedFattyAcid: string | number;
+
+    /**
+     * 单不饱和脂肪酸
+     */
+    monounsaturatedFattyAcid: string | number;
+
+    /**
+     * 多不饱和脂肪酸
+     */
+    polyunsaturatedFattyAcid: string | number;
+
+    /**
+     * 维生素A
+     */
+    vitaminA: number;
+
+    /**
+     * 维生素A(胡萝卜素)
+     */
+    vitaminACarotene: number;
+
+    /**
+     * 维生素A醇
+     */
+    vitaminAAlcohol: number;
+
+    /**
+     * 维生素D
+     */
+    vitaminD: number;
+
+    /**
+     * 维生素E
+     */
+    vitaminE: number;
+
+    /**
+     * 维生素E(生育酚)
+     */
+    vitaminETocopherol: number;
+
+    /**
+     * 维生素K
+     */
+    vitaminK: number;
+
+    /**
+     * 维生素B1
+     */
+    vitaminBOne: number;
+
+    /**
+     * 维生素B2
+     */
+    vitaminBTwo: number;
+
+    /**
+     * 维生素B6
+     */
+    vitaminBSix: number;
+
+    /**
+     * 维生素B12
+     */
+    vitaminBTwelve: number;
+
+    /**
+     * 烟酸(尼克酸)
+     */
+    niacin: number;
+
+    /**
+     * 维生素C
+     */
+    vitaminC: number;
+
+    /**
+     * 叶酸
+     */
+    folicAcid: string | number;
+
+    /**
+     * 胆碱
+     */
+    choline: number;
+
+    /**
+     * 生物素
+     */
+    biotin: number;
+
+    /**
+     * 泛酸
+     */
+    pantothenicAcid: string | number;
+
+    /**
+     * 胆固醇
+     */
+    cholesterol: number;
+
+    /**
+     * 血糖生成指数
+     */
+    bloodGlucoseIndex: number;
+
+    /**
+     * 不可溶性膳食纤维
+     */
+    insolubleDietaryFiber: number;
+
+    /**
+     * 膳食纤维
+     */
+    dietaryFiber: number;
+
+    /**
+     * 灰分
+     */
+    ash: number;
+
+    /**
+     * 可溶性膳食纤维
+     */
+    solubleDietaryFiber: number;
+
+    /**
+     * 适用人群
+     */
+    applicableCrowd: string;
+
+    /**
+     * 不适用人群
+     */
+    unsuitableCrowd: string;
+
+    /**
+     * 渗透压
+     */
+    osmoticPressure: number;
+
+    /**
+     * 原料
+     */
+    rawMaterial: string;
+
+    /**
+     * 适应症及禁忌
+     */
+    indicationsContraindications: string;
+
+    /**
+     * 食用方法和食用量
+     */
+    usageAndDosage: string;
+
+    /**
+     * 产品特点
+     */
+    productFeatures: string;
+
+    /**
+     * 储存条件
+     */
+    storageConditions: string;
+
+    /**
+     * 警示说明及注意事项
+     */
+    warningInstructions: string;
+
+    /**
+     * 商品附件
+     */
+    productAttachments: string;
+
+    /**
+     * 状态(1:启用 0:禁用)
+     */
+    status: number;
+
+    /**
+     * 上架 
+     */
+    putFlag: string;
+
+    /**
+     * 出库文号
+     */
+    outboundNumber: string;
+
+    /**
+     * 水分
+     */
+    moisture: number;
+
+}
+
+export interface NutritionForm extends BaseEntity {
+    /**
+     * 主键ID
+     */
+    id?: string | number;
+
+    /**
+     * 产品名称
+     */
+    productName?: string;
+
+    /**
+     * 院方系统编码
+     */
+    hospitalSystemCode?: string;
+
+    /**
+     * 商品编码
+     */
+    productCode?: string;
+
+    /**
+     * 产品所属分类
+     */
+    productCategory?: string;
+
+    productCategoryList?: string[];
+
+    /**
+     * 生产厂商
+     */
+    manufacturer?: string;
+
+    /**
+     * 品牌
+     */
+    brand?: string;
+
+    /**
+     * 产品所属标签
+     */
+    productLabel?: string;
+
+    /**
+     * 许可证有效期提醒
+     */
+    licenseExpiryReminder?: string;
+
+    /**
+     * 商品许可证有效期至
+     */
+    productLicenseExpiry?: string;
+
+    /**
+     * 商品资质
+     */
+    productQualification?: string;
+
+    /**
+     * 批准文号
+     */
+    approvalNumber?: string;
+
+    /**
+     * 口味
+     */
+    taste?: string;
+
+    /**
+     * 剂型/形态
+     */
+    dosageForm?: string;
+
+    /**
+     * 供应商
+     */
+    supplier?: string;
+
+    /**
+     * 产品适用科室
+     */
+    applicableDepartment?: string;
+
+    /**
+     * 禁忌症所属标签
+     */
+    contraindicationLabel?: string;
+
+    /**
+     * 保质期临期提醒
+     */
+    shelfLifeReminder?: string;
+
+    /**
+     * 保质期
+     */
+    shelfLife?: string;
+
+    /**
+     * 入货价格
+     */
+    purchasePrice?: number;
+
+    /**
+     * 入货单位
+     */
+    purchaseUnit?: string;
+
+    /**
+     * 默认用法
+     */
+    defaultUsage?: string;
+
+    /**
+     * 预包装单位
+     */
+    packageUnit?: string;
+
+    /**
+     * 商品规格
+     */
+    productSpec?: string;
+
+    /**
+     * 商品规格-数值
+     */
+    productSpecValue?: string;
+
+    /**
+     * 商品规格-单位
+     */
+    productSpecUnit?: string;
+
+    /**
+     * 预包装销售价
+     */
+    packagePrice?: number;
+
+    /**
+     * 最小包装单位
+     */
+    minUnit?: string;
+
+    /**
+     * 最小包装规格
+     */
+    minSpec?: string;
+
+    /**
+     * 净含量/规格
+     */
+    netContent?: string;
+
+    /**
+     * 配置销售价格
+     */
+    configSalePrice?: number;
+
+    /**
+     * 配置损耗率
+     */
+    configLossRate?: number;
+
+    /**
+     * 热量
+     */
+    calorie?: number;
+
+    /**
+     * 碳水化合物
+     */
+    carbohydrate?: number;
+
+    /**
+     * 热能
+     */
+    heatEnergy?: number;
+
+    /**
+     * 蛋白质
+     */
+    protein?: number;
+
+    /**
+     * 脂肪
+     */
+    fat?: number;
+
+    /**
+     * 钙
+     */
+    ca?: number;
+
+    /**
+     * 磷
+     */
+    p?: number;
+
+    /**
+     * 钾
+     */
+    k?: number;
+
+    /**
+     * 钠
+     */
+    na?: number;
+
+    /**
+     * 镁
+     */
+    mg?: number;
+
+    /**
+     * 氯
+     */
+    cl?: number;
+
+    /**
+     * 铁
+     */
+    fe?: number;
+
+    /**
+     * 锌
+     */
+    zn?: number;
+
+    /**
+     * 硒
+     */
+    se?: number;
+
+    /**
+     * 铜
+     */
+    cu?: number;
+
+    /**
+     * 锰
+     */
+    mn?: number;
+
+    /**
+     * 碘
+     */
+    i?: number;
+
+    /**
+     * 氟
+     */
+    f?: number;
+
+    /**
+     * 铬
+     */
+    cr?: number;
+
+    /**
+     * 钼
+     */
+    mo?: number;
+
+    /**
+     * 异亮氨酸
+     */
+    isoleucine?: number;
+
+    /**
+     * 色氨酸
+     */
+    tryptophan?: number;
+
+    /**
+     * 含硫氨基酸
+     */
+    sulfurAminoAcid?: string | number;
+
+    /**
+     * 组氨酸
+     */
+    histidine?: string | number;
+
+    /**
+     * 芳香族氨基酸
+     */
+    aromaticAminoAcid?: string | number;
+
+    /**
+     * 谷氨酸
+     */
+    glutamicAcid?: string | number;
+
+    /**
+     * 苏氨酸
+     */
+    threonine?: number;
+
+    /**
+     * 丝氨酸
+     */
+    serine?: number;
+
+    /**
+     * 精氨酸
+     */
+    arginine?: number;
+
+    /**
+     * 赖氨酸
+     */
+    lysine?: number;
+
+    /**
+     * 天冬氨酸
+     */
+    asparticAcid?: string | number;
+
+    /**
+     * 胱氨酸
+     */
+    cysteine?: number;
+
+    /**
+     * 脯氨酸
+     */
+    proline?: number;
+
+    /**
+     * 酪氨酸
+     */
+    tyrosine?: number;
+
+    /**
+     * 亮氨酸
+     */
+    leucine?: number;
+
+    /**
+     * 缬氨酸
+     */
+    valine?: number;
+
+    /**
+     * 蛋氨酸
+     */
+    methionine?: number;
+
+    /**
+     * 丙氨酸
+     */
+    alanine?: number;
+
+    /**
+     * 苯丙氨酸
+     */
+    phenylalanine?: number;
+
+    /**
+     * 甘氨酸
+     */
+    glycine?: number;
+
+    /**
+     * 脂肪酸
+     */
+    fattyAcid?: string | number;
+
+    /**
+     * 饱和脂肪酸
+     */
+    saturatedFattyAcid?: string | number;
+
+    /**
+     * 单不饱和脂肪酸
+     */
+    monounsaturatedFattyAcid?: string | number;
+
+    /**
+     * 多不饱和脂肪酸
+     */
+    polyunsaturatedFattyAcid?: string | number;
+
+    /**
+     * 维生素A
+     */
+    vitaminA?: number;
+
+    /**
+     * 维生素A(胡萝卜素)
+     */
+    vitaminACarotene?: number;
+
+    /**
+     * 维生素A醇
+     */
+    vitaminAAlcohol?: number;
+
+    /**
+     * 维生素D
+     */
+    vitaminD?: number;
+
+    /**
+     * 维生素E
+     */
+    vitaminE?: number;
+
+    /**
+     * 维生素E(生育酚)
+     */
+    vitaminETocopherol?: number;
+
+    /**
+     * 维生素K
+     */
+    vitaminK?: number;
+
+    /**
+     * 维生素B1
+     */
+    vitaminBOne?: number;
+
+    /**
+     * 维生素B2
+     */
+    vitaminBTwo?: number;
+
+    /**
+     * 维生素B6
+     */
+    vitaminBSix?: number;
+
+    /**
+     * 维生素B12
+     */
+    vitaminBTwelve?: number;
+
+    /**
+     * 烟酸(尼克酸)
+     */
+    niacin?: number;
+
+    /**
+     * 维生素C
+     */
+    vitaminC?: number;
+
+    /**
+     * 叶酸
+     */
+    folicAcid?: string | number;
+
+    /**
+     * 胆碱
+     */
+    choline?: number;
+
+    /**
+     * 生物素
+     */
+    biotin?: number;
+
+    /**
+     * 泛酸
+     */
+    pantothenicAcid?: string | number;
+
+    /**
+     * 胆固醇
+     */
+    cholesterol?: number;
+
+    /**
+     * 血糖生成指数
+     */
+    bloodGlucoseIndex?: number;
+
+    /**
+     * 不可溶性膳食纤维
+     */
+    insolubleDietaryFiber?: number;
+
+    /**
+     * 膳食纤维
+     */
+    dietaryFiber?: number;
+
+    /**
+     * 灰分
+     */
+    ash?: number;
+
+    /**
+     * 可溶性膳食纤维
+     */
+    solubleDietaryFiber?: number;
+
+    /**
+     * 适用人群
+     */
+    applicableCrowd?: string;
+
+    /**
+     * 不适用人群
+     */
+    unsuitableCrowd?: string;
+
+    /**
+     * 渗透压
+     */
+    osmoticPressure?: number;
+
+    /**
+     * 原料
+     */
+    rawMaterial?: string;
+
+    /**
+     * 适应症及禁忌
+     */
+    indicationsContraindications?: string;
+
+    /**
+     * 食用方法和食用量
+     */
+    usageAndDosage?: string;
+
+    /**
+     * 产品特点
+     */
+    productFeatures?: string;
+
+    /**
+     * 储存条件
+     */
+    storageConditions?: string;
+
+    /**
+     * 警示说明及注意事项
+     */
+    warningInstructions?: string;
+
+    /**
+     * 商品附件
+     */
+    productAttachments?: string;
+
+    /**
+     * 状态(1:启用 0:禁用)
+     */
+    status?: number;
+
+    /**
+     * 上架 
+     */
+    putFlag?: string;
+
+    /**
+     * 出库文号
+     */
+    outboundNumber?: string;
+
+    /**
+     * 水分
+     */
+    moisture?: number;
+
+}
+
+export interface NutritionQuery extends PageQuery {
+
+    /**
+     * 产品名称
+     */
+    productName?: string;
+
+    /**
+     * 院方系统编码
+     */
+    hospitalSystemCode?: string;
+
+    /**
+     * 商品编码
+     */
+    productCode?: string;
+
+    /**
+     * 产品所属分类
+     */
+    productCategory?: string;
+
+    productCategoryList?: string[];
+
+    /**
+     * 生产厂商
+     */
+    manufacturer?: string;
+
+    /**
+     * 品牌
+     */
+    brand?: string;
+
+    /**
+     * 产品所属标签
+     */
+    productLabel?: string;
+
+    /**
+     * 许可证有效期提醒
+     */
+    licenseExpiryReminder?: string;
+
+    /**
+     * 商品许可证有效期至
+     */
+    productLicenseExpiry?: string;
+
+    /**
+     * 商品资质
+     */
+    productQualification?: string;
+
+    /**
+     * 批准文号
+     */
+    approvalNumber?: string;
+
+    /**
+     * 口味
+     */
+    taste?: string;
+
+    /**
+     * 剂型/形态
+     */
+    dosageForm?: string;
+
+    /**
+     * 供应商
+     */
+    supplier?: string;
+
+    /**
+     * 产品适用科室
+     */
+    applicableDepartment?: string;
+
+    /**
+     * 禁忌症所属标签
+     */
+    contraindicationLabel?: string;
+
+    /**
+     * 保质期临期提醒
+     */
+    shelfLifeReminder?: string;
+
+    /**
+     * 保质期
+     */
+    shelfLife?: string;
+
+    /**
+     * 入货价格
+     */
+    purchasePrice?: number;
+
+    /**
+     * 入货单位
+     */
+    purchaseUnit?: string;
+
+    /**
+     * 默认用法
+     */
+    defaultUsage?: string;
+
+    /**
+     * 预包装单位
+     */
+    packageUnit?: string;
+
+    /**
+     * 商品规格
+     */
+    productSpec?: string;
+
+    /**
+     * 预包装销售价
+     */
+    packagePrice?: number;
+
+    /**
+     * 最小包装单位
+     */
+    minUnit?: string;
+
+    /**
+     * 最小包装规格
+     */
+    minSpec?: string;
+
+    /**
+     * 净含量/规格
+     */
+    netContent?: string;
+
+    /**
+     * 配置销售价格
+     */
+    configSalePrice?: number;
+
+    /**
+     * 配置损耗率
+     */
+    configLossRate?: number;
+
+    /**
+     * 热量
+     */
+    calorie?: number;
+
+    /**
+     * 碳水化合物
+     */
+    carbohydrate?: number;
+
+    /**
+     * 热能
+     */
+    heatEnergy?: number;
+
+    /**
+     * 蛋白质
+     */
+    protein?: number;
+
+    /**
+     * 脂肪
+     */
+    fat?: number;
+
+    /**
+     * 钙
+     */
+    ca?: number;
+
+    /**
+     * 磷
+     */
+    p?: number;
+
+    /**
+     * 钾
+     */
+    k?: number;
+
+    /**
+     * 钠
+     */
+    na?: number;
+
+    /**
+     * 镁
+     */
+    mg?: number;
+
+    /**
+     * 氯
+     */
+    cl?: number;
+
+    /**
+     * 铁
+     */
+    fe?: number;
+
+    /**
+     * 锌
+     */
+    zn?: number;
+
+    /**
+     * 硒
+     */
+    se?: number;
+
+    /**
+     * 铜
+     */
+    cu?: number;
+
+    /**
+     * 锰
+     */
+    mn?: number;
+
+    /**
+     * 碘
+     */
+    i?: number;
+
+    /**
+     * 氟
+     */
+    f?: number;
+
+    /**
+     * 铬
+     */
+    cr?: number;
+
+    /**
+     * 钼
+     */
+    mo?: number;
+
+    /**
+     * 异亮氨酸
+     */
+    isoleucine?: number;
+
+    /**
+     * 色氨酸
+     */
+    tryptophan?: number;
+
+    /**
+     * 含硫氨基酸
+     */
+    sulfurAminoAcid?: string | number;
+
+    /**
+     * 组氨酸
+     */
+    histidine?: string | number;
+
+    /**
+     * 芳香族氨基酸
+     */
+    aromaticAminoAcid?: string | number;
+
+    /**
+     * 谷氨酸
+     */
+    glutamicAcid?: string | number;
+
+    /**
+     * 苏氨酸
+     */
+    threonine?: number;
+
+    /**
+     * 丝氨酸
+     */
+    serine?: number;
+
+    /**
+     * 精氨酸
+     */
+    arginine?: number;
+
+    /**
+     * 赖氨酸
+     */
+    lysine?: number;
+
+    /**
+     * 天冬氨酸
+     */
+    asparticAcid?: string | number;
+
+    /**
+     * 胱氨酸
+     */
+    cysteine?: number;
+
+    /**
+     * 脯氨酸
+     */
+    proline?: number;
+
+    /**
+     * 酪氨酸
+     */
+    tyrosine?: number;
+
+    /**
+     * 亮氨酸
+     */
+    leucine?: number;
+
+    /**
+     * 缬氨酸
+     */
+    valine?: number;
+
+    /**
+     * 蛋氨酸
+     */
+    methionine?: number;
+
+    /**
+     * 丙氨酸
+     */
+    alanine?: number;
+
+    /**
+     * 苯丙氨酸
+     */
+    phenylalanine?: number;
+
+    /**
+     * 甘氨酸
+     */
+    glycine?: number;
+
+    /**
+     * 脂肪酸
+     */
+    fattyAcid?: string | number;
+
+    /**
+     * 饱和脂肪酸
+     */
+    saturatedFattyAcid?: string | number;
+
+    /**
+     * 单不饱和脂肪酸
+     */
+    monounsaturatedFattyAcid?: string | number;
+
+    /**
+     * 多不饱和脂肪酸
+     */
+    polyunsaturatedFattyAcid?: string | number;
+
+    /**
+     * 维生素A
+     */
+    vitaminA?: number;
+
+    /**
+     * 维生素A(胡萝卜素)
+     */
+    vitaminACarotene?: number;
+
+    /**
+     * 维生素A醇
+     */
+    vitaminAAlcohol?: number;
+
+    /**
+     * 维生素D
+     */
+    vitaminD?: number;
+
+    /**
+     * 维生素E
+     */
+    vitaminE?: number;
+
+    /**
+     * 维生素E(生育酚)
+     */
+    vitaminETocopherol?: number;
+
+    /**
+     * 维生素K
+     */
+    vitaminK?: number;
+
+    /**
+     * 维生素B1
+     */
+    vitaminBOne?: number;
+
+    /**
+     * 维生素B2
+     */
+    vitaminBTwo?: number;
+
+    /**
+     * 维生素B6
+     */
+    vitaminBSix?: number;
+
+    /**
+     * 维生素B12
+     */
+    vitaminBTwelve?: number;
+
+    /**
+     * 烟酸(尼克酸)
+     */
+    niacin?: number;
+
+    /**
+     * 维生素C
+     */
+    vitaminC?: number;
+
+    /**
+     * 叶酸
+     */
+    folicAcid?: string | number;
+
+    /**
+     * 胆碱
+     */
+    choline?: number;
+
+    /**
+     * 生物素
+     */
+    biotin?: number;
+
+    /**
+     * 泛酸
+     */
+    pantothenicAcid?: string | number;
+
+    /**
+     * 胆固醇
+     */
+    cholesterol?: number;
+
+    /**
+     * 血糖生成指数
+     */
+    bloodGlucoseIndex?: number;
+
+    /**
+     * 不可溶性膳食纤维
+     */
+    insolubleDietaryFiber?: number;
+
+    /**
+     * 膳食纤维
+     */
+    dietaryFiber?: number;
+
+    /**
+     * 灰分
+     */
+    ash?: number;
+
+    /**
+     * 可溶性膳食纤维
+     */
+    solubleDietaryFiber?: number;
+
+    /**
+     * 适用人群
+     */
+    applicableCrowd?: string;
+
+    /**
+     * 不适用人群
+     */
+    unsuitableCrowd?: string;
+
+    /**
+     * 渗透压
+     */
+    osmoticPressure?: number;
+
+    /**
+     * 原料
+     */
+    rawMaterial?: string;
+
+    /**
+     * 适应症及禁忌
+     */
+    indicationsContraindications?: string;
+
+    /**
+     * 食用方法和食用量
+     */
+    usageAndDosage?: string;
+
+    /**
+     * 产品特点
+     */
+    productFeatures?: string;
+
+    /**
+     * 储存条件
+     */
+    storageConditions?: string;
+
+    /**
+     * 警示说明及注意事项
+     */
+    warningInstructions?: string;
+
+    /**
+     * 商品附件
+     */
+    productAttachments?: string;
+
+    /**
+     * 状态(1:启用 0:禁用)
+     */
+    status?: number;
+
+    /**
+     * 上架 
+     */
+    putFlag?: string;
+
+    /**
+     * 出库文号
+     */
+    outboundNumber?: string;
+
+    /**
+     * 水分
+     */
+    moisture?: number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

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

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/warehouse/suppliesCategory/types';
+
+/**
+ * 查询耗材分类列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listSuppliesCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
+  return request({
+    url: '/warehouse/supplies/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询耗材分类详细
+ * @param categoryId
+ */
+export const getSuppliesCategory = (categoryId: string | number): AxiosPromise<CategoryVO> => {
+  return request({
+    url: '/warehouse/supplies/' + categoryId,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增耗材分类
+ * @param data
+ */
+export const addSuppliesCategory = (data: CategoryForm) => {
+  return request({
+    url: '/warehouse/supplies',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改耗材分类
+ * @param data
+ */
+export const updateSuppliesCategory = (data: CategoryForm) => {
+  return request({
+    url: '/warehouse/supplies',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除耗材分类
+ * @param categoryId
+ */
+export const delSuppliesCategory = (categoryId: string | number | Array<string | number>) => {
+  return request({
+    url: '/warehouse/supplies/' + categoryId,
+    method: 'delete'
+  });
+};

+ 71 - 0
src/api/warehouse/suppliesCategory/types.ts

@@ -0,0 +1,71 @@
+export interface CategoryVO {
+  /**
+   * 耗材分类ID
+   */
+  categoryId: string | number;
+
+  /**
+   * 父耗材分类id
+   */
+  parentId: string | number;
+
+  /**
+   * 耗材分类名称
+   */
+  categoryName: string;
+
+  /**
+   * 显示顺序
+   */
+  orderNum: number;
+
+}
+
+export interface CategoryForm extends BaseEntity {
+  /**
+   * 耗材分类ID
+   */
+  categoryId?: string | number;
+
+  /**
+   * 父耗材分类id
+   */
+  parentId?: string | number;
+
+  /**
+   * 耗材分类名称
+   */
+  categoryName?: string;
+
+  /**
+   * 显示顺序
+   */
+  orderNum?: number;
+
+}
+
+export interface CategoryQuery extends PageQuery {
+
+  /**
+   * 父耗材分类id
+   */
+  parentId?: string | number;
+
+  /**
+   * 耗材分类名称
+   */
+  categoryName?: string;
+
+  /**
+   * 显示顺序
+   */
+  orderNum?: number;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

+ 63 - 0
src/api/workbench/treatmentUser/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { TreatmentUserVo, TreatmentUserForm, TreatmentUserQuery } from '@/api/workbench/treatmentUser/types';
+
+/**
+ * 查询待诊患者列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listTreatmentUser = (query?: TreatmentUserQuery): AxiosPromise<TreatmentUserVo[]> => {
+    return request({
+        url: '/workbench/treatmentUser/list',
+        method: 'get',
+        params: query
+    });
+};
+
+/**
+ * 查询待诊患者详细
+ * @param id
+ */
+export const getTreatmentUser = (id: string | number): AxiosPromise<TreatmentUserVo> => {
+    return request({
+        url: '/workbench/treatmentUser/' + id,
+        method: 'get'
+    });
+};
+
+/**
+ * 新增待诊患者
+ * @param data
+ */
+export const addTreatmentUser = (data: TreatmentUserForm) => {
+    return request({
+        url: '/workbench/treatmentUser',
+        method: 'post',
+        data: data
+    });
+};
+
+/**
+ * 修改待诊患者
+ * @param data
+ */
+export const updateTreatmentUser = (data: TreatmentUserForm) => {
+    return request({
+        url: '/workbench/treatmentUser',
+        method: 'put',
+        data: data
+    });
+};
+
+/**
+ * 删除待诊患者
+ * @param id
+ */
+export const delTreatmentUser = (id: string | number | Array<string | number>) => {
+    return request({
+        url: '/workbench/treatmentUser/' + id,
+        method: 'delete'
+    });
+};

+ 296 - 0
src/api/workbench/treatmentUser/types.ts

@@ -0,0 +1,296 @@
+export interface TreatmentUserVo {
+  /**
+   * 
+   */
+  id: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type: string;
+
+  /**
+   * 诊疗卡号
+   */
+  treatNum: string;
+
+  /**
+   * 门诊号
+   */
+  outpatientNo: string;
+
+  /**
+   * 科室
+   */
+  doorId: string | number;
+
+  /**
+   * 姓名
+   */
+  treatName: string;
+
+  /**
+   * 出生日期
+   */
+  birthday: string;
+
+  /**
+   * 联系电话
+   */
+  phoneNum: string;
+
+  /**
+   * 性别 
+   */
+  sex: string;
+
+  /**
+   * 身份证号
+   */
+  idCard: string | number;
+
+  /**
+   * 年龄
+   */
+  age: string;
+
+  /**
+   * 身高
+   */
+  height: string;
+
+  /**
+   * 体重
+   */
+  weight: string;
+
+  /**
+   * 过敏食物
+   */
+  allergyFoot: string;
+
+  /**
+   * 过敏药物
+   */
+  allergyDrug: string;
+
+  /**
+   * 体力活动
+   */
+  activity: string;
+
+  /**
+   * 床号
+   */
+  bedNo: string;
+
+  /**
+   * 病区
+   */
+  inpatientWard: string;
+
+  /**
+   * 入院时间
+   */
+  admissionDate: string;
+
+}
+
+export interface TreatmentUserForm extends BaseEntity {
+ /**
+   * 
+   */
+  id?: string | number;
+
+  /**
+   * 看诊类型
+   */
+  type?: string;
+
+  /**
+   * 诊疗卡号
+   */
+  treatNum?: string;
+
+  /**
+   * 门诊号
+   */
+  outpatientNo?: string;
+
+  /**
+   * 科室
+   */
+  doorId?: string | number;
+
+  /**
+   * 姓名
+   */
+  treatName?: string;
+
+  /**
+   * 出生日期
+   */
+  birthday?: string;
+
+  /**
+   * 联系电话
+   */
+  phoneNum?: string;
+
+  /**
+   * 性别 
+   */
+  sex?: string;
+
+  /**
+   * 身份证号
+   */
+  idCard?: string | number;
+
+  /**
+   * 年龄
+   */
+  age?: string;
+
+  /**
+   * 身高
+   */
+  height?: string;
+
+  /**
+   * 体重
+   */
+  weight?: string;
+
+  /**
+   * 过敏食物
+   */
+  allergyFoot?: string;
+
+  /**
+   * 过敏药物
+   */
+  allergyDrug?: string;
+
+  /**
+   * 体力活动
+   */
+  activity?: string;
+
+  /**
+   * 床号
+   */
+  bedNo?: string;
+
+  /**
+   * 病区
+   */
+  inpatientWard?: string;
+
+  /**
+   * 入院时间
+   */
+  admissionDate?: string;
+
+}
+
+export interface TreatmentUserQuery extends PageQuery {
+
+ /**
+   * 看诊类型
+   */
+  type?: string;
+
+  /**
+   * 诊疗卡号
+   */
+  treatNum?: string;
+
+  /**
+   * 门诊号
+   */
+  outpatientNo?: string;
+
+  /**
+   * 科室
+   */
+  doorId?: string | number;
+
+  /**
+   * 姓名
+   */
+  treatName?: string;
+
+  /**
+   * 出生日期
+   */
+  birthday?: string;
+
+  /**
+   * 联系电话
+   */
+  phoneNum?: string;
+
+  /**
+   * 性别 
+   */
+  sex?: string;
+
+  /**
+   * 身份证号
+   */
+  idCard?: string | number;
+
+  /**
+   * 年龄
+   */
+  age?: string;
+
+  /**
+   * 身高
+   */
+  height?: string;
+
+  /**
+   * 体重
+   */
+  weight?: string;
+
+  /**
+   * 过敏食物
+   */
+  allergyFoot?: string;
+
+  /**
+   * 过敏药物
+   */
+  allergyDrug?: string;
+
+  /**
+   * 体力活动
+   */
+  activity?: string;
+
+  /**
+   * 床号
+   */
+  bedNo?: string;
+
+  /**
+   * 病区
+   */
+  inpatientWard?: string;
+
+  /**
+   * 入院时间
+   */
+  admissionDate?: string;
+
+    /**
+     * 日期范围参数
+     */
+    params?: any;
+}
+
+
+

BIN
src/assets/images/empty.png


+ 50 - 0
src/utils/tree.ts

@@ -0,0 +1,50 @@
+import type { CategoryVO } from '@/api/warehouse/productCategory/types';
+
+interface TreeNode extends CategoryVO {
+  children?: TreeNode[];
+}
+
+/**
+ * 构造树型结构数据
+ * @param {Array} data 数据源
+ * @param {string} id id字段 默认 'id'
+ * @param {string} parentId 父节点字段 默认 'parentId'
+ * @param {string} children 孩子节点字段 默认 'children'
+ */
+export const handleTree = (data: TreeNode[], id = 'id', parentId = 'parentId', children = 'children'): TreeNode[] => {
+  const config = {
+    id,
+    parentId,
+    children
+  };
+
+  const childrenListMap = new Map();
+  const nodeIds = new Set();
+  const tree: TreeNode[] = [];
+
+  for (const item of data) {
+    const pId = item[config.parentId];
+    if (childrenListMap.has(pId)) {
+      childrenListMap.get(pId).push(item);
+    } else {
+      childrenListMap.set(pId, [item]);
+    }
+    nodeIds.add(item[config.id]);
+  }
+
+  for (const item of data) {
+    if (!nodeIds.has(item[config.parentId])) {
+      tree.push(item);
+    }
+  }
+
+  for (const [, children] of childrenListMap) {
+    for (const node of children) {
+      if (childrenListMap.has(node[config.id])) {
+        node[config.children] = childrenListMap.get(node[config.id]);
+      }
+    }
+  }
+
+  return tree;
+} 

+ 1 - 1
src/views/system/dict/data.vue

@@ -169,7 +169,7 @@ const initFormData: DictDataForm = {
   dictLabel: '',
   dictValue: '',
   cssClass: '',
-  listClass: 'primary',
+  listClass: 'default',
   dictSort: 0,
   remark: ''
 };

+ 603 - 661
src/views/system/user/index.vue

@@ -1,668 +1,610 @@
 <template>
-  <div class="p-2">
-    <el-row :gutter="20">
-      <!-- 部门树 -->
-      <el-col :lg="4" :xs="24" style="">
-        <el-card shadow="hover">
-          <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
-          <el-tree
-            ref="deptTreeRef"
-            class="mt-2"
-            node-key="id"
-            :data="deptOptions"
-            :props="{ label: 'label', children: 'children' } as any"
-            :expand-on-click-node="false"
-            :filter-node-method="filterNode"
-            highlight-current
-            default-expand-all
-            @node-click="handleNodeClick"
-          />
-        </el-card>
-      </el-col>
-      <el-col :lg="20" :xs="24">
-        <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">
-                <el-form-item label="用户名称" prop="userName">
-                  <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
-                </el-form-item>
-                <el-form-item label="用户昵称" prop="nickName">
-                  <el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable @keyup.enter="handleQuery" />
-                </el-form-item>
-                <el-form-item label="手机号码" prop="phonenumber">
-                  <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
-                </el-form-item>
-
-                <el-form-item label="状态" prop="status">
-                  <el-select v-model="queryParams.status" placeholder="用户状态" clearable>
-                    <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
-                  </el-select>
-                </el-form-item>
-                <el-form-item label="创建时间" style="width: 308px">
-                  <el-date-picker
-                    v-model="dateRange"
-                    value-format="YYYY-MM-DD HH:mm:ss"
-                    type="daterange"
-                    range-separator="-"
-                    start-placeholder="开始日期"
-                    end-placeholder="结束日期"
-                    :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
-                  ></el-date-picker>
-                </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="hover">
-          <template #header>
-            <el-row :gutter="10">
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
-                  修改
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
-                  删除
-                </el-button>
-              </el-col>
-              <el-col :span="1.5">
-                <el-dropdown class="mt-[1px]">
-                  <el-button plain type="info">
-                    更多
-                    <el-icon class="el-icon--right"><arrow-down /></el-icon
-                  ></el-button>
-                  <template #dropdown>
-                    <el-dropdown-menu>
-                      <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
-                      <!-- 注意 由于el-dropdown-item标签是延迟加载的 所以v-has-permi自定义标签不生效 需要使用v-if调用方法执行 -->
-                      <el-dropdown-item v-if="checkPermi(['system:user:import'])" icon="Top" @click="handleImport">导入数据</el-dropdown-item>
-                      <el-dropdown-item v-if="checkPermi(['system:user:export'])" icon="Download" @click="handleExport">导出数据</el-dropdown-item>
-                    </el-dropdown-menu>
-                  </template>
-                </el-dropdown>
-              </el-col>
-              <right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
-            </el-row>
-          </template>
-
-          <el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange">
-            <el-table-column type="selection" width="50" align="center" />
-            <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
-            <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
-            <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
-            <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
-              <template #default="scope">
-                <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
-              </template>
-            </el-table-column>
-
-            <el-table-column v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160">
-              <template #default="scope">
-                <span>{{ scope.row.createTime }}</span>
-              </template>
-            </el-table-column>
-
-            <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
-              <template #default="scope">
-                <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
-                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
-                </el-tooltip>
-                <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
-                  <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
-                </el-tooltip>
-
-                <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
-                  <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
-                </el-tooltip>
-
-                <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
-                  <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
-                </el-tooltip>
-              </template>
-            </el-table-column>
-          </el-table>
-
-          <pagination
-            v-show="total > 0"
-            v-model:page="queryParams.pageNum"
-            v-model:limit="queryParams.pageSize"
-            :total="total"
-            @pagination="getList"
-          />
-        </el-card>
-      </el-col>
-    </el-row>
-
-    <!-- 添加或修改用户配置对话框 -->
-    <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
-      <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="用户昵称" prop="nickName">
-              <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="归属部门" prop="deptId">
-              <el-tree-select
-                v-model="form.deptId"
-                :data="enabledDeptOptions"
-                :props="{ value: 'id', label: 'label', children: 'children' } as any"
-                value-key="id"
-                placeholder="请选择归属部门"
-                check-strictly
-                @change="handleDeptChange"
-              />
-            </el-form-item>
-          </el-col>
+    <div class="p-2">
+        <el-row :gutter="20">
+            <!-- 部门树 -->
+            <el-col :lg="4" :xs="24" style="">
+                <el-card shadow="hover">
+                    <el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
+                    <el-tree ref="deptTreeRef" class="mt-2" node-key="id" :data="deptOptions" :props="{ label: 'label', children: 'children' } as any" :expand-on-click-node="false" :filter-node-method="filterNode" highlight-current default-expand-all @node-click="handleNodeClick" />
+                </el-card>
+            </el-col>
+            <el-col :lg="20" :xs="24">
+                <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">
+                                <el-form-item label="用户名称" prop="userName">
+                                    <el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable @keyup.enter="handleQuery" />
+                                </el-form-item>
+                                <el-form-item label="用户昵称" prop="nickName">
+                                    <el-input v-model="queryParams.nickName" placeholder="请输入用户昵称" clearable @keyup.enter="handleQuery" />
+                                </el-form-item>
+                                <el-form-item label="手机号码" prop="phonenumber">
+                                    <el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable @keyup.enter="handleQuery" />
+                                </el-form-item>
+
+                                <el-form-item label="状态" prop="status">
+                                    <el-select v-model="queryParams.status" placeholder="用户状态" clearable>
+                                        <el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                    </el-select>
+                                </el-form-item>
+                                <el-form-item label="创建时间" style="width: 308px">
+                                    <el-date-picker v-model="dateRange" value-format="YYYY-MM-DD HH:mm:ss" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"></el-date-picker>
+                                </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="hover">
+                    <template #header>
+                        <el-row :gutter="10">
+                            <el-col :span="1.5">
+                                <el-button v-has-permi="['system:user:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
+                            </el-col>
+                            <el-col :span="1.5">
+                                <el-button v-has-permi="['system:user:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">
+                                    修改
+                                </el-button>
+                            </el-col>
+                            <el-col :span="1.5">
+                                <el-button v-has-permi="['system:user:remove']" type="danger" plain :disabled="multiple" icon="Delete" @click="handleDelete()">
+                                    删除
+                                </el-button>
+                            </el-col>
+                            <el-col :span="1.5">
+                                <el-dropdown class="mt-[1px]">
+                                    <el-button plain type="info">
+                                        更多
+                                        <el-icon class="el-icon--right">
+                                            <arrow-down />
+                                        </el-icon>
+                                    </el-button>
+                                    <template #dropdown>
+                                        <el-dropdown-menu>
+                                            <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
+                                            <!-- 注意 由于el-dropdown-item标签是延迟加载的 所以v-has-permi自定义标签不生效 需要使用v-if调用方法执行 -->
+                                            <el-dropdown-item v-if="checkPermi(['system:user:import'])" icon="Top" @click="handleImport">导入数据</el-dropdown-item>
+                                            <el-dropdown-item v-if="checkPermi(['system:user:export'])" icon="Download" @click="handleExport">导出数据</el-dropdown-item>
+                                        </el-dropdown-menu>
+                                    </template>
+                                </el-dropdown>
+                            </el-col>
+                            <right-toolbar v-model:show-search="showSearch" :columns="columns" :search="true" @query-table="getList"></right-toolbar>
+                        </el-row>
+                    </template>
+
+                    <el-table v-loading="loading" border :data="userList" @selection-change="handleSelectionChange">
+                        <el-table-column type="selection" width="50" align="center" />
+                        <el-table-column v-if="columns[0].visible" key="userId" label="用户编号" align="center" prop="userId" />
+                        <el-table-column v-if="columns[1].visible" key="userName" label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
+                        <el-table-column v-if="columns[2].visible" key="nickName" label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
+                        <el-table-column v-if="columns[3].visible" key="deptName" label="部门" align="center" prop="deptName" :show-overflow-tooltip="true" />
+                        <el-table-column v-if="columns[4].visible" key="phonenumber" label="手机号码" align="center" prop="phonenumber" width="120" />
+                        <el-table-column v-if="columns[5].visible" key="status" label="状态" align="center">
+                            <template #default="scope">
+                                <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
+                            </template>
+                        </el-table-column>
+
+                        <el-table-column v-if="columns[6].visible" label="创建时间" align="center" prop="createTime" width="160">
+                            <template #default="scope">
+                                <span>{{ scope.row.createTime }}</span>
+                            </template>
+                        </el-table-column>
+
+                        <el-table-column label="操作" fixed="right" width="180" class-name="small-padding fixed-width">
+                            <template #default="scope">
+                                <el-tooltip v-if="scope.row.userId !== 1" content="修改" placement="top">
+                                    <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
+                                </el-tooltip>
+                                <el-tooltip v-if="scope.row.userId !== 1" content="删除" placement="top">
+                                    <el-button v-hasPermi="['system:user:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
+                                </el-tooltip>
+
+                                <el-tooltip v-if="scope.row.userId !== 1" content="重置密码" placement="top">
+                                    <el-button v-hasPermi="['system:user:resetPwd']" link type="primary" icon="Key" @click="handleResetPwd(scope.row)"></el-button>
+                                </el-tooltip>
+
+                                <el-tooltip v-if="scope.row.userId !== 1" content="分配角色" placement="top">
+                                    <el-button v-hasPermi="['system:user:edit']" link type="primary" icon="CircleCheck" @click="handleAuthRole(scope.row)"></el-button>
+                                </el-tooltip>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+
+                    <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
+                </el-card>
+            </el-col>
         </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="手机号码" prop="phonenumber">
-              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="邮箱" prop="email">
-              <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
-              <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
-              <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="用户性别">
-              <el-select v-model="form.sex" placeholder="请选择">
-                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="状态">
-              <el-radio-group v-model="form.status">
-                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
-              </el-radio-group>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="12">
-            <el-form-item label="岗位">
-              <el-select v-model="form.postIds" multiple placeholder="请选择">
-                <el-option
-                  v-for="item in postOptions"
-                  :key="item.postId"
-                  :label="item.postName"
-                  :value="item.postId"
-                  :disabled="item.status == '1'"
-                ></el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="12">
-            <el-form-item label="角色" prop="roleIds">
-              <el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
-                <el-option
-                  v-for="item in roleOptions"
-                  :key="item.roleId"
-                  :label="item.roleName"
-                  :value="item.roleId"
-                  :disabled="item.status == '1'"
-                ></el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="24">
-            <el-form-item label="备注">
-              <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-form>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitForm">确 定</el-button>
-          <el-button @click="cancel()">取 消</el-button>
-        </div>
-      </template>
-    </el-dialog>
-
-    <!-- 用户导入对话框 -->
-    <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
-      <el-upload
-        ref="uploadRef"
-        :limit="1"
-        accept=".xlsx, .xls"
-        :headers="upload.headers"
-        :action="upload.url + '?updateSupport=' + upload.updateSupport"
-        :disabled="upload.isUploading"
-        :on-progress="handleFileUploadProgress"
-        :on-success="handleFileSuccess"
-        :auto-upload="false"
-        drag
-      >
-        <el-icon class="el-icon--upload">
-          <i-ep-upload-filled />
-        </el-icon>
-        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
-        <template #tip>
-          <div class="text-center el-upload__tip">
-            <div class="el-upload__tip"><el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
-            <span>仅允许导入xls、xlsx格式文件。</span>
-            <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
-          </div>
-        </template>
-      </el-upload>
-      <template #footer>
-        <div class="dialog-footer">
-          <el-button type="primary" @click="submitFileForm">确 定</el-button>
-          <el-button @click="upload.open = false">取 消</el-button>
-        </div>
-      </template>
-    </el-dialog>
-  </div>
+
+        <!-- 添加或修改用户配置对话框 -->
+        <el-dialog ref="formDialogRef" v-model="dialog.visible" :title="dialog.title" width="600px" append-to-body @close="closeDialog">
+            <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item label="用户昵称" prop="nickName">
+                            <el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="归属部门" prop="deptId">
+                            <el-tree-select v-model="form.deptId" :data="enabledDeptOptions" :props="{ value: 'id', label: 'label', children: 'children' } as any" value-key="id" placeholder="请选择归属部门" check-strictly @change="handleDeptChange" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item label="手机号码" prop="phonenumber">
+                            <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="邮箱" prop="email">
+                            <el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
+                            <el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
+                            <el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item label="用户性别">
+                            <el-select v-model="form.sex" placeholder="请选择">
+                                <el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="状态">
+                            <el-radio-group v-model="form.status">
+                                <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
+                            </el-radio-group>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row>
+                    <el-col :span="12">
+                        <el-form-item label="岗位">
+                            <el-select v-model="form.postIds" multiple placeholder="请选择">
+                                <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == '1'"></el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="角色" prop="roleIds">
+                            <el-select v-model="form.roleIds" filterable multiple placeholder="请选择">
+                                <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == '1'"></el-option>
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row>
+                    <el-col :span="24">
+                        <el-form-item label="备注">
+                            <el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button type="primary" @click="submitForm">确 定</el-button>
+                    <el-button @click="cancel()">取 消</el-button>
+                </div>
+            </template>
+        </el-dialog>
+
+        <!-- 用户导入对话框 -->
+        <el-dialog v-model="upload.open" :title="upload.title" width="400px" append-to-body>
+            <el-upload ref="uploadRef" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
+                <el-icon class="el-icon--upload">
+                    <i-ep-upload-filled />
+                </el-icon>
+                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+                <template #tip>
+                    <div class="text-center el-upload__tip">
+                        <div class="el-upload__tip">
+                            <el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据</div>
+                        <span>仅允许导入xls、xlsx格式文件。</span>
+                        <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
+                    </div>
+                </template>
+            </el-upload>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button type="primary" @click="submitFileForm">确 定</el-button>
+                    <el-button @click="upload.open = false">取 消</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
 </template>
 
 <script setup name="User" lang="ts">
-import api from '@/api/system/user';
-import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
-import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
-import { RoleVO } from '@/api/system/role/types';
-import { PostQuery, PostVO } from '@/api/system/post/types';
-import { treeselect } from '@/api/system/dept';
-import { globalHeaders } from '@/utils/request';
-import { to } from 'await-to-js';
-import { optionselect } from '@/api/system/post';
-import { hasPermi } from '@/directive/permission';
-import { checkPermi } from '@/utils/permission';
-
-const router = useRouter();
-const { proxy } = getCurrentInstance() as ComponentInternalInstance;
-const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
-const userList = ref<UserVO[]>();
-const loading = ref(true);
-const showSearch = ref(true);
-const ids = ref<Array<number | string>>([]);
-const single = ref(true);
-const multiple = ref(true);
-const total = ref(0);
-const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
-const deptName = ref('');
-const deptOptions = ref<DeptTreeVO[]>([]);
-const enabledDeptOptions = ref<DeptTreeVO[]>([]);
-const initPassword = ref<string>('');
-const postOptions = ref<PostVO[]>([]);
-const roleOptions = ref<RoleVO[]>([]);
-/*** 用户导入参数 */
-const upload = reactive<ImportOption>({
-  // 是否显示弹出层(用户导入)
-  open: false,
-  // 弹出层标题(用户导入)
-  title: '',
-  // 是否禁用上传
-  isUploading: false,
-  // 是否更新已经存在的用户数据
-  updateSupport: 0,
-  // 设置上传的请求头部
-  headers: globalHeaders(),
-  // 上传的地址
-  url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
-});
-// 列显隐信息
-const columns = ref<FieldOption[]>([
-  { key: 0, label: `用户编号`, visible: false, children: [] },
-  { key: 1, label: `用户名称`, visible: true, children: [] },
-  { key: 2, label: `用户昵称`, visible: true, children: [] },
-  { key: 3, label: `部门`, visible: true, children: [] },
-  { key: 4, label: `手机号码`, visible: true, children: [] },
-  { key: 5, label: `状态`, visible: true, children: [] },
-  { key: 6, label: `创建时间`, visible: true, children: [] }
-]);
-
-const deptTreeRef = ref<ElTreeInstance>();
-const queryFormRef = ref<ElFormInstance>();
-const userFormRef = ref<ElFormInstance>();
-const uploadRef = ref<ElUploadInstance>();
-const formDialogRef = ref<ElDialogInstance>();
-
-const dialog = reactive<DialogOption>({
-  visible: false,
-  title: ''
-});
-
-const initFormData: UserForm = {
-  userId: undefined,
-  deptId: undefined,
-  userName: '',
-  nickName: undefined,
-  password: '',
-  phonenumber: undefined,
-  email: undefined,
-  sex: undefined,
-  status: '0',
-  remark: '',
-  postIds: [],
-  roleIds: []
-};
-
-const initData: PageData<UserForm, UserQuery> = {
-  form: { ...initFormData },
-  queryParams: {
-    pageNum: 1,
-    pageSize: 10,
-    userName: '',
-    phonenumber: '',
-    status: '',
-    deptId: '',
-    roleId: ''
-  },
-  rules: {
-    userName: [
-      { required: true, message: '用户名称不能为空', trigger: 'blur' },
-      {
-        min: 2,
-        max: 20,
-        message: '用户名称长度必须介于 2 和 20 之间',
-        trigger: 'blur'
-      }
-    ],
-    nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
-    password: [
-      { required: true, message: '用户密码不能为空', trigger: 'blur' },
-      {
-        min: 5,
-        max: 20,
-        message: '用户密码长度必须介于 5 和 20 之间',
-        trigger: 'blur'
-      },
-      { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' }
-    ],
-    email: [
-      {
-        type: 'email',
-        message: '请输入正确的邮箱地址',
-        trigger: ['blur', 'change']
-      }
-    ],
-    phonenumber: [
-      {
-        pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
-        message: '请输入正确的手机号码',
-        trigger: 'blur'
-      }
-    ],
-    roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
-  }
-};
-const data = reactive<PageData<UserForm, UserQuery>>(initData);
-
-const { queryParams, form, rules } = toRefs<PageData<UserForm, UserQuery>>(data);
-
-/** 通过条件过滤节点  */
-const filterNode = (value: string, data: any) => {
-  if (!value) return true;
-  return data.label.indexOf(value) !== -1;
-};
-/** 根据名称筛选部门树 */
-watchEffect(
-  () => {
-    deptTreeRef.value?.filter(deptName.value);
-  },
-  {
-    flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
-  }
-);
-
-/** 查询用户列表 */
-const getList = async () => {
-  loading.value = true;
-  const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
-  loading.value = false;
-  userList.value = res.rows;
-  total.value = res.total;
-};
-
-/** 查询部门下拉树结构 */
-const getDeptTree = async () => {
-  const res = await api.deptTreeSelect();
-  deptOptions.value = res.data;
-  enabledDeptOptions.value = filterDisabledDept(res.data);
-};
-
-/** 过滤禁用的部门 */
-const filterDisabledDept = (deptList: DeptTreeVO[]) => {
-  return deptList.filter((dept) => {
-    if (dept.disabled) {
-      return false;
-    }
-    if (dept.children && dept.children.length) {
-      dept.children = filterDisabledDept(dept.children);
-    }
-    return true;
-  });
-};
-
-/** 节点单击事件 */
-const handleNodeClick = (data: DeptVO) => {
-  queryParams.value.deptId = data.id;
-  handleQuery();
-};
-
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.value.pageNum = 1;
-  getList();
-};
-/** 重置按钮操作 */
-const resetQuery = () => {
-  dateRange.value = ['', ''];
-  queryFormRef.value?.resetFields();
-  queryParams.value.pageNum = 1;
-  queryParams.value.deptId = undefined;
-  deptTreeRef.value?.setCurrentKey(undefined);
-  handleQuery();
-};
-
-/** 删除按钮操作 */
-const handleDelete = async (row?: UserVO) => {
-  const userIds = row?.userId || ids.value;
-  const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
-  if (!err) {
-    await api.delUser(userIds);
-    await getList();
-    proxy?.$modal.msgSuccess('删除成功');
-  }
-};
-
-/** 用户状态修改  */
-const handleStatusChange = async (row: UserVO) => {
-  const text = row.status === '0' ? '启用' : '停用';
-  try {
-    await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
-    await api.changeUserStatus(row.userId, row.status);
-    proxy?.$modal.msgSuccess(text + '成功');
-  } catch (err) {
-    row.status = row.status === '0' ? '1' : '0';
-  }
-};
-/** 跳转角色分配 */
-const handleAuthRole = (row: UserVO) => {
-  const userId = row.userId;
-  router.push('/system/user-auth/role/' + userId);
-};
-
-/** 重置密码按钮操作 */
-const handleResetPwd = async (row: UserVO) => {
-  const [err, res] = await to(
-    ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', {
-      confirmButtonText: '确定',
-      cancelButtonText: '取消',
-      closeOnClickModal: false,
-      inputPattern: /^.{5,20}$/,
-      inputErrorMessage: '用户密码长度必须介于 5 和 20 之间',
-      inputValidator: (value) => {
-        if (/<|>|"|'|\||\\/.test(value)) {
-          return '不能包含非法字符:< > " \' \\ |';
+    import api from '@/api/system/user';
+    import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
+    import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
+    import { RoleVO } from '@/api/system/role/types';
+    import { PostQuery, PostVO } from '@/api/system/post/types';
+    import { treeselect } from '@/api/system/dept';
+    import { globalHeaders } from '@/utils/request';
+    import { to } from 'await-to-js';
+    import { optionselect } from '@/api/system/post';
+    import { hasPermi } from '@/directive/permission';
+    import { checkPermi } from '@/utils/permission';
+
+    const router = useRouter();
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+    const { sys_normal_disable, sys_user_sex } = toRefs < any > (proxy ?.useDict('sys_normal_disable', 'sys_user_sex'));
+    const userList = ref < UserVO[] > ();
+    const loading = ref(true);
+    const showSearch = ref(true);
+    const ids = ref < Array < number | string >> ([]);
+    const single = ref(true);
+    const multiple = ref(true);
+    const total = ref(0);
+    const dateRange = ref < [DateModelType, DateModelType] > (['', '']);
+    const deptName = ref('');
+    const deptOptions = ref < DeptTreeVO[] > ([]);
+    const enabledDeptOptions = ref < DeptTreeVO[] > ([]);
+    const initPassword = ref < string > ('');
+    const postOptions = ref < PostVO[] > ([]);
+    const roleOptions = ref < RoleVO[] > ([]);
+    /*** 用户导入参数 */
+    const upload = reactive < ImportOption > ({
+        // 是否显示弹出层(用户导入)
+        open: false,
+        // 弹出层标题(用户导入)
+        title: '',
+        // 是否禁用上传
+        isUploading: false,
+        // 是否更新已经存在的用户数据
+        updateSupport: 0,
+        // 设置上传的请求头部
+        headers: globalHeaders(),
+        // 上传的地址
+        url: import.meta.env.VITE_APP_BASE_API + '/system/user/importData'
+    });
+    // 列显隐信息
+    const columns = ref < FieldOption[] > ([
+        { key: 0, label: `用户编号`, visible: false, children: [] },
+        { key: 1, label: `用户名称`, visible: true, children: [] },
+        { key: 2, label: `用户昵称`, visible: true, children: [] },
+        { key: 3, label: `部门`, visible: true, children: [] },
+        { key: 4, label: `手机号码`, visible: true, children: [] },
+        { key: 5, label: `状态`, visible: true, children: [] },
+        { key: 6, label: `创建时间`, visible: true, children: [] }
+    ]);
+
+    const deptTreeRef = ref < ElTreeInstance > ();
+    const queryFormRef = ref < ElFormInstance > ();
+    const userFormRef = ref < ElFormInstance > ();
+    const uploadRef = ref < ElUploadInstance > ();
+    const formDialogRef = ref < ElDialogInstance > ();
+
+    const dialog = reactive < DialogOption > ({
+        visible: false,
+        title: ''
+    });
+
+    const initFormData: UserForm = {
+        userId: undefined,
+        deptId: undefined,
+        userName: '',
+        nickName: undefined,
+        password: '',
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: '0',
+        remark: '',
+        postIds: [],
+        roleIds: []
+    };
+
+    const initData: PageData < UserForm, UserQuery > = {
+        form: { ...initFormData },
+        queryParams: {
+            pageNum: 1,
+            pageSize: 10,
+            userName: '',
+            phonenumber: '',
+            status: '',
+            deptId: '',
+            roleId: ''
+        },
+        rules: {
+            userName: [
+                { required: true, message: '用户名称不能为空', trigger: 'blur' },
+                {
+                    min: 2,
+                    max: 20,
+                    message: '用户名称长度必须介于 2 和 20 之间',
+                    trigger: 'blur'
+                }
+            ],
+            nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
+            password: [
+                { required: true, message: '用户密码不能为空', trigger: 'blur' },
+                {
+                    min: 5,
+                    max: 20,
+                    message: '用户密码长度必须介于 5 和 20 之间',
+                    trigger: 'blur'
+                },
+                { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' }
+            ],
+            email: [{
+                type: 'email',
+                message: '请输入正确的邮箱地址',
+                trigger: ['blur', 'change']
+            }],
+            phonenumber: [{
+                pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+                message: '请输入正确的手机号码',
+                trigger: 'blur'
+            }],
+            roleIds: [{ required: true, message: '用户角色不能为空', trigger: 'blur' }]
+        }
+    };
+    const data = reactive < PageData < UserForm,
+        UserQuery >> (initData);
+
+    const { queryParams, form, rules } = toRefs < PageData < UserForm, UserQuery >> (data);
+
+    /** 通过条件过滤节点  */
+    const filterNode = (value: string, data: any) => {
+        if (!value) return true;
+        return data.label.indexOf(value) !== -1;
+    };
+    /** 根据名称筛选部门树 */
+    watchEffect(
+        () => {
+            deptTreeRef.value ?.filter(deptName.value);
+        }, {
+            flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
+        }
+    );
+
+    /** 查询用户列表 */
+    const getList = async () => {
+        loading.value = true;
+        const res = await api.listUser(proxy ?.addDateRange(queryParams.value, dateRange.value));
+        loading.value = false;
+        userList.value = res.rows;
+        total.value = res.total;
+    };
+
+    /** 查询部门下拉树结构 */
+    const getDeptTree = async () => {
+        const res = await api.deptTreeSelect();
+        deptOptions.value = res.data;
+        enabledDeptOptions.value = filterDisabledDept(res.data);
+    };
+
+    /** 过滤禁用的部门 */
+    const filterDisabledDept = (deptList: DeptTreeVO[]) => {
+        return deptList.filter((dept) => {
+            if (dept.disabled) {
+                return false;
+            }
+            if (dept.children && dept.children.length) {
+                dept.children = filterDisabledDept(dept.children);
+            }
+            return true;
+        });
+    };
+
+    /** 节点单击事件 */
+    const handleNodeClick = (data: DeptVO) => {
+        queryParams.value.deptId = data.id;
+        handleQuery();
+    };
+
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        queryParams.value.pageNum = 1;
+        getList();
+    };
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        dateRange.value = ['', ''];
+        queryFormRef.value ?.resetFields();
+        queryParams.value.pageNum = 1;
+        queryParams.value.deptId = undefined;
+        deptTreeRef.value ?.setCurrentKey(undefined);
+        handleQuery();
+    };
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row ? : UserVO) => {
+        const userIds = row ?.userId || ids.value;
+        const [err] = await to(proxy ?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
+        if (!err) {
+            await api.delUser(userIds);
+            await getList();
+            proxy ?.$modal.msgSuccess('删除成功');
+        }
+    };
+
+    /** 用户状态修改  */
+    const handleStatusChange = async (row: UserVO) => {
+        const text = row.status === '0' ? '启用' : '停用';
+        try {
+            await proxy ?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
+            await api.changeUserStatus(row.userId, row.status);
+            proxy ?.$modal.msgSuccess(text + '成功');
+        } catch (err) {
+            row.status = row.status === '0' ? '1' : '0';
         }
-      }
-    })
-  );
-  if (!err && res) {
-    await api.resetUserPwd(row.userId, res.value);
-    proxy?.$modal.msgSuccess('修改成功,新密码是:' + res.value);
-  }
-};
-
-/** 选择条数  */
-const handleSelectionChange = (selection: UserVO[]) => {
-  ids.value = selection.map((item) => item.userId);
-  single.value = selection.length != 1;
-  multiple.value = !selection.length;
-};
-
-/** 导入按钮操作 */
-const handleImport = () => {
-  upload.title = '用户导入';
-  upload.open = true;
-};
-/** 导出按钮操作 */
-const handleExport = () => {
-  proxy?.download(
-    'system/user/export',
-    {
-      ...queryParams.value
-    },
-    `user_${new Date().getTime()}.xlsx`
-  );
-};
-/** 下载模板操作 */
-const importTemplate = () => {
-  proxy?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
-};
-
-/**文件上传中处理 */
-const handleFileUploadProgress = () => {
-  upload.isUploading = true;
-};
-/** 文件上传成功处理 */
-const handleFileSuccess = (response: any, file: UploadFile) => {
-  upload.open = false;
-  upload.isUploading = false;
-  uploadRef.value?.handleRemove(file);
-  ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
-    dangerouslyUseHTMLString: true
-  });
-  getList();
-};
-
-/** 提交上传文件 */
-function submitFileForm() {
-  uploadRef.value?.submit();
-}
-
-/** 重置操作表单 */
-const reset = () => {
-  form.value = { ...initFormData };
-  userFormRef.value?.resetFields();
-};
-/** 取消按钮 */
-const cancel = () => {
-  dialog.visible = false;
-  reset();
-};
-
-/** 新增按钮操作 */
-const handleAdd = async () => {
-  reset();
-  const { data } = await api.getUser();
-  dialog.visible = true;
-  dialog.title = '新增用户';
-  postOptions.value = data.posts;
-  roleOptions.value = data.roles;
-  form.value.password = initPassword.value.toString();
-};
-
-/** 修改按钮操作 */
-const handleUpdate = async (row?: UserForm) => {
-  reset();
-  const userId = row?.userId || ids.value[0];
-  const { data } = await api.getUser(userId);
-  dialog.visible = true;
-  dialog.title = '修改用户';
-  Object.assign(form.value, data.user);
-  postOptions.value = data.posts;
-  roleOptions.value = data.roles;
-  form.value.postIds = data.postIds;
-  form.value.roleIds = data.roleIds;
-  form.value.password = '';
-};
-
-/** 提交按钮 */
-const submitForm = () => {
-  userFormRef.value?.validate(async (valid: boolean) => {
-    if (valid) {
-      form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
-      proxy?.$modal.msgSuccess('操作成功');
-      dialog.visible = false;
-      await getList();
+    };
+    /** 跳转角色分配 */
+    const handleAuthRole = (row: UserVO) => {
+        const userId = row.userId;
+        router.push('/system/user-auth/role/' + userId);
+    };
+
+    /** 重置密码按钮操作 */
+    const handleResetPwd = async (row: UserVO) => {
+        const [err, res] = await to(
+            ElMessageBox.prompt('请输入"' + row.userName + '"的新密码', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                closeOnClickModal: false,
+                inputPattern: /^.{5,20}$/,
+                inputErrorMessage: '用户密码长度必须介于 5 和 20 之间',
+                inputValidator: (value) => {
+                    if (/<|>|"|'|\||\\/.test(value)) {
+                        return '不能包含非法字符:< > " \' \\ |';
+                    }
+                }
+            })
+        );
+        if (!err && res) {
+            await api.resetUserPwd(row.userId, res.value);
+            proxy ?.$modal.msgSuccess('修改成功,新密码是:' + res.value);
+        }
+    };
+
+    /** 选择条数  */
+    const handleSelectionChange = (selection: UserVO[]) => {
+        ids.value = selection.map((item) => item.userId);
+        single.value = selection.length != 1;
+        multiple.value = !selection.length;
+    };
+
+    /** 导入按钮操作 */
+    const handleImport = () => {
+        upload.title = '用户导入';
+        upload.open = true;
+    };
+    /** 导出按钮操作 */
+    const handleExport = () => {
+        proxy ?.download(
+            'system/user/export', {
+                ...queryParams.value
+            },
+            `user_${new Date().getTime()}.xlsx`
+        );
+    };
+    /** 下载模板操作 */
+    const importTemplate = () => {
+        proxy ?.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`);
+    };
+
+    /**文件上传中处理 */
+    const handleFileUploadProgress = () => {
+        upload.isUploading = true;
+    };
+    /** 文件上传成功处理 */
+    const handleFileSuccess = (response: any, file: UploadFile) => {
+        upload.open = false;
+        upload.isUploading = false;
+        uploadRef.value ?.handleRemove(file);
+        ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + '</div>', '导入结果', {
+            dangerouslyUseHTMLString: true
+        });
+        getList();
+    };
+
+    /** 提交上传文件 */
+    function submitFileForm() {
+        uploadRef.value ?.submit();
+    }
+
+    /** 重置操作表单 */
+    const reset = () => {
+        form.value = { ...initFormData };
+        userFormRef.value ?.resetFields();
+    };
+    /** 取消按钮 */
+    const cancel = () => {
+        dialog.visible = false;
+        reset();
+    };
+
+    /** 新增按钮操作 */
+    const handleAdd = async () => {
+        reset();
+        const { data } = await api.getUser();
+        dialog.visible = true;
+        dialog.title = '新增用户';
+        postOptions.value = data.posts;
+        roleOptions.value = data.roles;
+        form.value.password = initPassword.value.toString();
+    };
+
+    /** 修改按钮操作 */
+    const handleUpdate = async (row ? : UserForm) => {
+        reset();
+        const userId = row ?.userId || ids.value[0];
+        const { data } = await api.getUser(userId);
+        dialog.visible = true;
+        dialog.title = '修改用户';
+        Object.assign(form.value, data.user);
+        postOptions.value = data.posts;
+        roleOptions.value = data.roles;
+        form.value.postIds = data.postIds;
+        form.value.roleIds = data.roleIds;
+        form.value.password = '';
+    };
+
+    /** 提交按钮 */
+    const submitForm = () => {
+        userFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
+                proxy ?.$modal.msgSuccess('操作成功');
+                dialog.visible = false;
+                await getList();
+            }
+        });
+    };
+
+    /**
+     * 关闭用户弹窗
+     */
+    const closeDialog = () => {
+        dialog.visible = false;
+        resetForm();
+    };
+
+    /**
+     * 重置表单
+     */
+    const resetForm = () => {
+        userFormRef.value ?.resetFields();
+        userFormRef.value ?.clearValidate();
+
+        form.value.id = undefined;
+        form.value.status = '1';
+    };
+    onMounted(() => {
+        getDeptTree(); // 初始化部门数据
+        getList(); // 初始化列表数据
+        proxy ?.getConfigKey('sys.user.initPassword').then((response) => {
+            initPassword.value = response.data;
+        });
+    });
+
+    async function handleDeptChange(value: number | string) {
+        const response = await optionselect(value);
+        postOptions.value = response.data;
+        form.value.postIds = [];
     }
-  });
-};
-
-/**
- * 关闭用户弹窗
- */
-const closeDialog = () => {
-  dialog.visible = false;
-  resetForm();
-};
-
-/**
- * 重置表单
- */
-const resetForm = () => {
-  userFormRef.value?.resetFields();
-  userFormRef.value?.clearValidate();
-
-  form.value.id = undefined;
-  form.value.status = '1';
-};
-onMounted(() => {
-  getDeptTree(); // 初始化部门数据
-  getList(); // 初始化列表数据
-  proxy?.getConfigKey('sys.user.initPassword').then((response) => {
-    initPassword.value = response.data;
-  });
-});
-
-async function handleDeptChange(value: number | string) {
-  const response = await optionselect(value);
-  postOptions.value = response.data;
-  form.value.postIds = [];
-}
-</script>
+</script>

+ 1537 - 0
src/views/warehouse/nutriProduct/index.vue

@@ -0,0 +1,1537 @@
+<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">
+                        <el-form-item label="产品分类" prop="productCategory">
+                            <el-cascader v-model="queryParams.productCategoryList" :options="categoryOptions" :props="{ checkStrictly: false, emitPath: true, value: 'value', label: 'label', children: 'children' }" placeholder="请选择" clearable filterable style="width: 200px" />
+                        </el-form-item>
+                        <el-form-item>
+                            <el-input v-model="queryParams.productName" placeholder="请输入名称/编码" clearable @keyup.enter="handleQuery" />
+                        </el-form-item>
+                        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+                    </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="['warehouse:nutrition:add']">新增营养产品</el-button>
+                    </el-col>
+                    <!-- <el-col :span="1.5">
+                        <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['warehouse:nutrition:edit']">修改</el-button>
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['warehouse:nutrition:remove']">删除</el-button>
+                    </el-col> -->
+                    <el-col :span="1.5">
+                        <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['warehouse:nutrition: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="nutritionList" @selection-change="handleSelectionChange">
+                <el-table-column type="selection" width="55" align="center" />
+                <el-table-column label="产品名称" align="center" prop="productName" />
+                <el-table-column label="商品编码" align="center" prop="productCode" />
+                <el-table-column label="产品分类" align="center">
+                    <template #default="{ row }">
+                        {{ getCategoryName(row.productCategory) }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="规格" align="center" prop="productSpec" />
+                <el-table-column label="剂型/形态" align="center">
+                    <template #default="{ row }">
+                        {{ dosage_form.find(item => item.value === row.dosageForm)?.label || row.dosageForm }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="许可证临期提醒" align="center" prop="productLicenseExpiry" width="180">
+                    <template #default="scope">
+                        <span>{{ scope.row.productLicenseExpiry ? parseTime(scope.row.productLicenseExpiry, '{y}-{m}-{d}') : '--' }}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="保质期临期提醒" align="center" prop="shelfLife" width="180">
+                    <template #default="scope">
+                        <span>{{ scope.row.shelfLife || '--' }}</span>
+                    </template>
+                </el-table-column>
+                <el-table-column label="上架状态" align="center" prop="putFlag" width="100">
+                    <template #default="{ row }">
+                        {{ put_flag.find(item => item.value === row.putFlag)?.label || row.putFlag }}
+                    </template>
+                </el-table-column>
+                <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
+                    <template #default="scope">
+                        <el-button v-if="scope.row.putFlag === '1'" link type="danger" @click="handlePutFlag(scope.row, '0')">下架</el-button>
+                        <el-button v-else link type="success" @click="handlePutFlag(scope.row, '1')">上架</el-button>
+                        <el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
+                    </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="70%" append-to-body class="nutrition-dialog">
+            <el-tabs v-model="activeTab">
+                <el-scrollbar height="calc(70vh - 120px)">
+                    <el-tab-pane label="基本信息" name="basic">
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-divider content-position="left">基本信息:</el-divider>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="产品名称:" prop="productName">
+                                        <el-input v-model="form.productName" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="商品资质:" prop="productQualification">
+                                        <el-select v-model="form.productQualification" placeholder="请选择" clearable>
+                                            <el-option v-for="dict in product_qualification" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="院方系统编码:" prop="hospitalSystemCode">
+                                        <el-input v-model="form.hospitalSystemCode" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="批准文号:" prop="approvalNumber">
+                                        <el-input v-model="form.approvalNumber" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+
+                            </el-row>
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="商品编码:" prop="productCode">
+                                        <el-input v-model="form.productCode" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="口味:" prop="taste">
+                                        <el-input v-model="form.taste" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="产品所属分类:" prop="productCategory">
+                                        <el-cascader v-model="form.productCategoryList" :options="categoryOptions" :props="{ checkStrictly: false, emitPath: true, value: 'value', label: 'label', children: 'children' }" placeholder="请选择" clearable filterable style="width: 100%" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="剂型/形态:" prop="dosageForm">
+                                        <el-select v-model="form.dosageForm" placeholder="请选择" clearable>
+                                            <el-option v-for="dict in dosage_form" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="生产厂商:" prop="manufacturer">
+                                        <el-select v-model="form.manufacturer" placeholder="请选择">
+                                            <el-option label="请选择" 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-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="品牌:" prop="brand">
+                                        <el-input v-model="form.brand" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="产品适用科室:" prop="applicableDepartment">
+                                        <el-select v-model="form.applicableDepartment" placeholder="请选择">
+                                            <el-option label="请选择" value="" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="产品所属标签:" prop="productLabel">
+                                        <el-select v-model="form.productLabel" placeholder="请选择">
+                                            <el-option label="请选择" value="" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="禁忌症所属标签:" prop="contraindicationLabel">
+                                        <el-select v-model="form.contraindicationLabel" placeholder="请选择">
+                                            <el-option label="请选择" value="" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="许可证临期提醒:" prop="licenseExpiryReminder">
+                                        <el-input v-model="form.licenseExpiryReminder" placeholder="请输入">
+                                            <template #append>个月</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="保质期临期提醒:" prop="shelfLifeReminder">
+                                        <el-input v-model="form.shelfLifeReminder" placeholder="请输入">
+                                            <template #append>个月</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="商品许可证有效期至:" prop="productLicenseExpiry">
+                                        <el-date-picker v-model="form.productLicenseExpiry" type="date" placeholder="请选择" value-format="YYYY-MM-DD" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="保质期:" prop="shelfLife">
+                                        <el-input v-model="form.shelfLife" placeholder="请输入">
+                                            <template #append>个月</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <!-- 入货配置部分 -->
+                            <el-divider content-position="left">入货信息:</el-divider>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="入货价格:" prop="purchasePrice" required>
+                                        <el-input v-model="form.purchasePrice" placeholder="请输入">
+                                            <template #append>元/盒</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="入货单位:" prop="purchaseUnit" required>
+                                        <el-select v-model="form.purchaseUnit" placeholder="请选择" clearable>
+                                            <el-option v-for="dict in product_package_unit" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="商品规格:" prop="productSpec" required>
+                                        <div style="display: flex; align-items: center;">
+                                            <el-input v-model="form.productSpec" placeholder="请输入" style="width: 500px; border-top-right-radius: 0; border-bottom-right-radius: 0;" :maxlength="10" />
+                                            <el-select v-model="form.productSpecUnit" style="width: 80px; border-radius: 0; border-left: none; border-top-left-radius: 0; border-bottom-left-radius: 0;" :popper-append-to-body="false" size="default" @change="onSpecUnitChange">
+                                                <el-option label="g" value="g" />
+                                                <el-option label="ml" value="ml" />
+                                                <el-option label="mg" value="mg" />
+                                            </el-select>
+                                            <span style="margin-left: 8px; color: #606266; font-size: 14px;">/包</span>
+                                        </div>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="预包装单位:" prop="packageUnit">
+                                        <el-select v-model="form.packageUnit" placeholder="请选择" clearable>
+                                            <el-option v-for="dict in product_package_unit" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                            <el-divider content-position="left">预包装销售设置:</el-divider>
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="预包装销售价:" prop="packagePrice" required>
+                                        <el-input v-model="form.packagePrice" placeholder="请输入">
+                                            <template #append>元/盒</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="最小包装单位:" prop="minUnit">
+                                        <el-select v-model="form.minUnit" placeholder="请选择" clearable>
+                                            <el-option v-for="dict in product_package_unit" :key="dict.value" :label="dict.label" :value="dict.value" />
+                                        </el-select>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="最小包装规格:" prop="minSpec">
+                                        <el-input v-model="form.minSpec" placeholder="请输入">
+                                            <template #append>g/包</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="净含量/规格:" prop="minUnit">
+                                        <span>--</span>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                            <el-divider content-position="left">配置销售设置::</el-divider>
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="配置销售价格:" prop="configSalePrice" required>
+                                        <el-input v-model="form.configSalePrice" placeholder="请输入">
+                                            <template #append>元/g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="配置损耗率:" prop="configLossRate">
+                                        <el-input v-model="form.configLossRate" placeholder="请输入">
+                                            <template #append>%</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="热能及三大营养素" name="nutrition">
+                        <span style="color: red; font-size: 16px; margin-bottom: 20px">注:每100(g/ml) 含量</span>
+
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="热量:" prop="calorie">
+                                        <el-input v-model="form.calorie" placeholder="请输入">
+                                            <template #append>kcal</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="蛋白质:" prop="protein">
+                                        <el-input v-model="form.protein" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="脂肪:" prop="fat">
+                                        <el-input v-model="form.fat" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="碳水化合物:" prop="carbohydrate">
+                                        <el-input v-model="form.carbohydrate" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="热能:" prop="heatEnergy">
+                                        <el-input v-model="form.heatEnergy" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="常量元素" name="macroElements">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="钙:" prop="ca">
+                                        <el-input v-model="form.ca" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="磷:" prop="p">
+                                        <el-input v-model="form.p" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="钾:" prop="k">
+                                        <el-input v-model="form.k" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="钠:" prop="na">
+                                        <el-input v-model="form.na" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="镁:" prop="mg">
+                                        <el-input v-model="form.mg" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="氯:" prop="cl">
+                                        <el-input v-model="form.cl" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="微量元素" name="microElements">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="铁:" prop="fe">
+                                        <el-input v-model="form.fe" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="锌:" prop="zn">
+                                        <el-input v-model="form.zn" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="硒:" prop="se">
+                                        <el-input v-model="form.se" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="铜:" prop="cu">
+                                        <el-input v-model="form.cu" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="锰:" prop="mn">
+                                        <el-input v-model="form.mn" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="碘:" prop="i">
+                                        <el-input v-model="form.i" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="氟:" prop="f">
+                                        <el-input v-model="form.f" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="铬:" prop="cr">
+                                        <el-input v-model="form.cr" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="钼:" prop="mo">
+                                        <el-input v-model="form.mo" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="氨基酸" name="aminoAcids">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="异亮氨酸:" prop="isoleucine">
+                                        <el-input v-model="form.isoleucine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="亮氨酸:" prop="leucine">
+                                        <el-input v-model="form.leucine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="赖氨酸:" prop="lysine">
+                                        <el-input v-model="form.lysine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="蛋氨酸:" prop="methionine">
+                                        <el-input v-model="form.methionine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="苯丙氨酸:" prop="phenylalanine">
+                                        <el-input v-model="form.phenylalanine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="苏氨酸:" prop="threonine">
+                                        <el-input v-model="form.threonine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="色氨酸:" prop="tryptophan">
+                                        <el-input v-model="form.tryptophan" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="缬氨酸:" prop="valine">
+                                        <el-input v-model="form.valine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="组氨酸:" prop="histidine">
+                                        <el-input v-model="form.histidine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="精氨酸:" prop="arginine">
+                                        <el-input v-model="form.arginine" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="脂肪酸" name="fattyAcids">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="饱和脂肪酸:" prop="saturatedFattyAcid">
+                                        <el-input v-model="form.saturatedFattyAcid" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="单不饱和脂肪酸:" prop="monounsaturatedFattyAcid">
+                                        <el-input v-model="form.monounsaturatedFattyAcid" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="多不饱和脂肪酸:" prop="polyunsaturatedFattyAcid">
+                                        <el-input v-model="form.polyunsaturatedFattyAcid" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="维生素" name="vitamins">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="维生素A:" prop="vitaminA">
+                                        <el-input v-model="form.vitaminA" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="维生素D:" prop="vitaminD">
+                                        <el-input v-model="form.vitaminD" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="维生素E:" prop="vitaminE">
+                                        <el-input v-model="form.vitaminE" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="维生素K:" prop="vitaminK">
+                                        <el-input v-model="form.vitaminK" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="维生素B1:" prop="vitaminBOne">
+                                        <el-input v-model="form.vitaminBOne" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="维生素B2:" prop="vitaminBTwo">
+                                        <el-input v-model="form.vitaminBTwo" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="维生素B6:" prop="vitaminBSix">
+                                        <el-input v-model="form.vitaminBSix" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="维生素B12:" prop="vitaminBTwelve">
+                                        <el-input v-model="form.vitaminBTwelve" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="维生素C:" prop="vitaminC">
+                                        <el-input v-model="form.vitaminC" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="叶酸:" prop="folicAcid">
+                                        <el-input v-model="form.folicAcid" placeholder="请输入">
+                                            <template #append>μg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="脂类" name="lipids">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="胆固醇:" prop="cholesterol">
+                                        <el-input v-model="form.cholesterol" placeholder="请输入">
+                                            <template #append>mg</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="其他" name="others">
+                        <span style="color: red; font-size: 16px; margin-bottom: 10px">注:每100(g/ml) 含量</span>
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px" style="margin-top:20px">
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="膳食纤维:" prop="dietaryFiber">
+                                        <el-input v-model="form.dietaryFiber" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="灰分:" prop="ash">
+                                        <el-input v-model="form.ash" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="不可溶性膳食纤维:" prop="insolubleDietaryFiber">
+                                        <el-input v-model="form.insolubleDietaryFiber" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="可溶性膳食纤维:" prop="solubleDietaryFiber">
+                                        <el-input v-model="form.solubleDietaryFiber" placeholder="请输入">
+                                            <template #append>g</template>
+                                        </el-input>
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+                            <el-row :gutter="20">
+                                <el-col :span="12">
+                                    <el-form-item label="血糖生成指数:" prop="bloodGlucoseIndex">
+                                        <el-input v-model="form.bloodGlucoseIndex" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="渗透压:" prop="osmoticPressure">
+                                        <el-input v-model="form.osmoticPressure" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="商品说明" name="productDescription">
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px">
+
+                            <el-row :gutter="20" style="margin-top:20px">
+                                <el-col :span="12">
+                                    <el-form-item label="适用人群:" prop="applicableCrowd">
+                                        <el-input v-model="form.applicableCrowd" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="原料:" prop="storageConditions">
+                                        <el-input v-model="form.storageConditions" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="食用方法和食用量:" prop="usageAndDosage">
+                                        <el-input v-model="form.usageAndDosage" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="储存条件:" prop="storageConditions">
+                                        <el-input v-model="form.storageConditions" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                                <el-col :span="12">
+                                    <el-form-item label="不适用人群:" prop="unsuitableCrowd">
+                                        <el-input v-model="form.unsuitableCrowd" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="渗透压:" prop="unsuitableCrowd">
+                                        <el-input v-model="form.unsuitableCrowd" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="适应症及禁忌:" prop="indicationsContraindications">
+                                        <el-input v-model="form.indicationsContraindications" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="产品特点:" prop="productFeatures">
+                                        <el-input v-model="form.productFeatures" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                    <el-form-item label="警示说明及注意事项:" prop="warningInstructions">
+                                        <el-input v-model="form.warningInstructions" type="textarea" maxlength="300" show-word-limit :rows="4" placeholder="请输入" />
+                                    </el-form-item>
+                                </el-col>
+                            </el-row>
+
+
+                        </el-form>
+                    </el-tab-pane>
+
+                    <el-tab-pane label="商品附件" name="productAttachments">
+                        <el-form ref="nutritionFormRef" :model="form" :rules="rules" label-width="200px" style="margin-top: 30px">
+                            <el-form-item label="商品附件" prop="productAttachments">
+                                <el-upload class="upload-demo" action="#" :auto-upload="false" :on-change="handleFileChange" :file-list="fileList" multiple>
+                                    <el-button type="primary">选择文件</el-button>
+                                    <template #tip>
+                                        <div class="el-upload__tip">支持上传jpg/png/pdf文件</div>
+                                    </template>
+                                </el-upload>
+                            </el-form-item>
+                        </el-form>
+                    </el-tab-pane>
+                </el-scrollbar>
+            </el-tabs>
+            <template #footer>
+                <div class="dialog-footer" style="text-align: center">
+                    <el-button type="primary" @click="submitForm">保存</el-button>
+                    <el-button type="primary" @click="submitFormAndPutaway">保存并上架</el-button>
+                </div>
+            </template>
+        </el-dialog>
+        <!-- 新增详情弹窗,内容全部静态分组展示,仿照a1.png -->
+        <el-dialog title="营养产品详情" v-model="detailDialogVisible" width="60%" append-to-body class="nutrition-dialog">
+            <el-tabs v-model="activeTab">
+                <el-scrollbar height="calc(80vh - 120px)">
+                    <el-tab-pane label="基本信息" name="basic">
+                        <el-divider content-position="left">基本信息:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>产品名称:</b>{{ form.productName || '--' }}</div>
+                                <div><b>院方系统编码:</b>{{ form.hospitalSystemCode || '--' }}</div>
+                                <div><b>商品编码:</b>{{ form.productCode || '--' }}</div>
+                                <div><b>产品所属分类:</b>{{ form.productCategory || '--' }}</div>
+                                <div><b>生产厂商:</b>{{ form.manufacturer || '--' }}</div>
+                                <div><b>品牌:</b>{{ form.brand || '--' }}</div>
+                                <div><b>产品所属标签:</b>{{ form.productLabel || '--' }}</div>
+                                <div><b>许可证临期提醒:</b>{{ form.licenseExpiryReminder || '--' }}</div>
+                                <div><b>商品许可证有效期至:</b>{{ form.productLicenseExpiry || '--' }}</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>商品资质:</b>{{ form.productQualification || '--' }}</div>
+                                <div><b>批准文号:</b>{{ form.approvalNumber || '--' }}</div>
+                                <div><b>口味:</b>{{ form.taste || '--' }}</div>
+                                <div><b>剂型/形态:</b>{{ form.dosageForm || '--' }}</div>
+                                <div><b>供应商:</b>{{ form.supplier || '--' }}</div>
+                                <div><b>产品适用科室:</b>{{ form.applicableDepartment || '--' }}</div>
+                                <div><b>禁忌症所属标签:</b>{{ form.contraindicationLabel || '--' }}</div>
+                                <div><b>保质期临期提醒:</b>{{ form.shelfLifeReminder || '--' }}</div>
+                                <div><b>保质期:</b>{{ form.shelfLife || '--' }}</div>
+                            </el-col>
+                        </el-row>
+                        <el-divider content-position="left">入货信息:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>入货价格:</b>{{ form.purchasePrice || '--' }} 元</div>
+                                <div><b>默认入货单位:</b>{{ form.purchaseUnit || '--' }}</div>
+                                <div><b>商品规格:</b>{{ form.productSpec || '--' }}/{{ form.productSpecUnit || '--' }}</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>入货单位:</b>{{ form.purchaseUnit || '--' }}</div>
+                                <div><b>预包装单位:</b>{{ form.packageUnit || '--' }}</div>
+                            </el-col>
+                        </el-row>
+                        <el-divider content-position="left">预包装销售设置:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>预包装销售价:</b>{{ form.packagePrice || '--' }} 元/袋</div>
+                                <div><b>最小包装规格:</b>{{ form.minSpec || '--' }} g/包</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>最小包装单位:</b>{{ form.minUnit || '--' }}</div>
+                                <div><b>净含量/规格:</b>{{ form.netContent || '--' }}</div>
+                            </el-col>
+                        </el-row>
+                        <el-divider content-position="left">配置销售设置:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>配置销售价格:</b>{{ form.configSalePrice || '--' }} 元/g</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>配置损耗率:</b>{{ form.configLossRate || '--' }} %</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="热能及三大营养素" name="nutrition">
+                        <el-divider content-position="left">热能及三大营养素:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>热量:</b>{{ form.calorie || '--' }} kcal</div>
+                                <div><b>脂肪:</b>{{ form.fat || '--' }} g</div>
+                                <div><b>热能:</b>{{ form.heatEnergy || '--' }} g</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>蛋白质:</b>{{ form.protein || '--' }} g</div>
+                                <div><b>碳水化合物:</b>{{ form.carbohydrate || '--' }} g</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="常量元素" name="macroElements">
+                        <el-divider content-position="left">常量元素:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>钙:</b>{{ form.ca || '--' }} mg</div>
+                                <div><b>钾:</b>{{ form.k || '--' }} mg</div>
+                                <div><b>镁:</b>{{ form.mg || '--' }} mg</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>磷:</b>{{ form.p || '--' }} mg</div>
+                                <div><b>钠:</b>{{ form.na || '--' }} mg</div>
+                                <div><b>氯:</b>{{ form.cl || '--' }} mg</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="微量元素" name="microElements">
+                        <el-divider content-position="left">微量元素:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>铁:</b>{{ form.fe || '--' }} mg</div>
+                                <div><b>硒:</b>{{ form.se || '--' }} μg</div>
+                                <div><b>锰:</b>{{ form.mn || '--' }} mg</div>
+                                <div><b>氟:</b>{{ form.f || '--' }} mg</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>锌:</b>{{ form.zn || '--' }} mg</div>
+                                <div><b>铜:</b>{{ form.cu || '--' }} mg</div>
+                                <div><b>碘:</b>{{ form.i || '--' }} μg</div>
+                                <div><b>铬:</b>{{ form.cr || '--' }} μg</div>
+                            </el-col>
+                        </el-row>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>钼:</b>{{ form.mo || '--' }} μg</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="氨基酸" name="aminoAcids">
+                        <el-divider content-position="left">氨基酸:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>异亮氨酸:</b>{{ form.isoleucine || '--' }} mg</div>
+                                <div><b>赖氨酸:</b>{{ form.lysine || '--' }} mg</div>
+                                <div><b>苯丙氨酸:</b>{{ form.phenylalanine || '--' }} mg</div>
+                                <div><b>组氨酸:</b>{{ form.histidine || '--' }} mg</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>亮氨酸:</b>{{ form.leucine || '--' }} mg</div>
+                                <div><b>蛋氨酸:</b>{{ form.methionine || '--' }} mg</div>
+                                <div><b>苏氨酸:</b>{{ form.threonine || '--' }} mg</div>
+                                <div><b>精氨酸:</b>{{ form.arginine || '--' }} mg</div>
+                            </el-col>
+                        </el-row>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>色氨酸:</b>{{ form.tryptophan || '--' }} mg</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>缬氨酸:</b>{{ form.valine || '--' }} mg</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="脂肪酸" name="fattyAcids">
+                        <el-divider content-position="left">脂肪酸:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>饱和脂肪酸:</b>{{ form.saturatedFattyAcid || '--' }} g</div>
+                                <div><b>多不饱和脂肪酸:</b>{{ form.polyunsaturatedFattyAcid || '--' }} g</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>单不饱和脂肪酸:</b>{{ form.monounsaturatedFattyAcid || '--' }} g</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="维生素" name="vitamins">
+                        <el-divider content-position="left">维生素:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>维生素A:</b>{{ form.vitaminA || '--' }} μg</div>
+                                <div><b>维生素E:</b>{{ form.vitaminE || '--' }} mg</div>
+                                <div><b>维生素B1:</b>{{ form.vitaminBOne || '--' }} mg</div>
+                                <div><b>维生素B6:</b>{{ form.vitaminBSix || '--' }} mg</div>
+                                <div><b>维生素C:</b>{{ form.vitaminC || '--' }} mg</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>维生素D:</b>{{ form.vitaminD || '--' }} μg</div>
+                                <div><b>维生素K:</b>{{ form.vitaminK || '--' }} μg</div>
+                                <div><b>维生素B2:</b>{{ form.vitaminBTwo || '--' }} mg</div>
+                                <div><b>维生素B12:</b>{{ form.vitaminBTwelve || '--' }} μg</div>
+                                <div><b>叶酸:</b>{{ form.folicAcid || '--' }} μg</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="脂类" name="lipids">
+                        <el-divider content-position="left">脂类:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>胆固醇:</b>{{ form.cholesterol || '--' }} mg</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="其他" name="others">
+                        <el-divider content-position="left">其他:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>膳食纤维:</b>{{ form.dietaryFiber || '--' }} g</div>
+                                <div><b>不可溶性膳食纤维:</b>{{ form.insolubleDietaryFiber || '--' }} g</div>
+                                <div><b>血糖生成指数:</b>{{ form.bloodGlucoseIndex || '--' }}</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>灰分:</b>{{ form.ash || '--' }} g</div>
+                                <div><b>可溶性膳食纤维:</b>{{ form.solubleDietaryFiber || '--' }} g</div>
+                                <div><b>渗透压:</b>{{ form.osmoticPressure || '--' }}</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="商品说明" name="productDescription">
+                        <el-divider content-position="left">商品说明:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="12">
+                                <div><b>适用人群:</b>{{ form.applicableCrowd || '--' }}</div>
+                                <div><b>原料:</b>{{ form.rawMaterial || '--' }}</div>
+                                <div><b>食用方法和食用量:</b>{{ form.usageAndDosage || '--' }}</div>
+                                <div><b>储存条件:</b>{{ form.storageConditions || '--' }}</div>
+                            </el-col>
+                            <el-col :span="12">
+                                <div><b>不适用人群:</b>{{ form.unsuitableCrowd || '--' }}</div>
+                                <div><b>适应症及禁忌:</b>{{ form.indicationsContraindications || '--' }}</div>
+                                <div><b>产品特点:</b>{{ form.productFeatures || '--' }}</div>
+                                <div><b>警示说明及注意事项:</b>{{ form.warningInstructions || '--' }}</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                    <el-tab-pane label="商品附件" name="productAttachments">
+                        <el-divider content-position="left">商品附件:</el-divider>
+                        <el-row :gutter="40">
+                            <el-col :span="24">
+                                <div v-if="form.productAttachments && form.productAttachments.length">
+                                    <div v-for="(file, idx) in form.productAttachments" :key="idx">
+                                        <a :href="file.url" target="_blank">{{ file.name }}</a>
+                                    </div>
+                                </div>
+                                <div v-else>--</div>
+                            </el-col>
+                        </el-row>
+                    </el-tab-pane>
+                </el-scrollbar>
+            </el-tabs>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="Nutrition" lang="ts">
+    import { listNutrition, getNutrition, delNutrition, addNutrition, updateNutrition } from '@/api/warehouse/productNutrition/index';
+    import { NutritionVO, NutritionQuery, NutritionForm } from '@/api/warehouse/productNutrition/types';
+    import { listCategory } from '@/api/warehouse/productCategory/index';
+
+    import { FormInstance, ElMessageBox, UploadFile, UploadFiles } from 'element-plus';
+    import { getCurrentInstance, ComponentInternalInstance, ref, reactive, toRefs, onMounted } from 'vue';
+    import { log } from 'console';
+
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+    const { product_qualification, dosage_form, product_package_unit, product_supplier, put_flag } = toRefs < any > (proxy ?.useDict('product_qualification', 'dosage_form', 'product_package_unit', 'product_supplier', 'put_flag'));
+
+
+    const nutritionList = ref < NutritionVO[] > ([]);
+    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 activeTab = ref('basic');
+    const fileList = ref < UploadFiles > ([]);
+    const detailDialogVisible = ref(false);
+
+    const treeData = ref([]); // 定义 treeData
+
+    const queryFormRef = ref < FormInstance > ();
+    const nutritionFormRef = ref < FormInstance > ();
+
+    const dialog = reactive < DialogOption > ({
+        visible: false,
+        title: ''
+    });
+
+    const initFormData: NutritionForm = {
+        id: undefined,
+        productName: undefined,
+        hospitalSystemCode: undefined,
+        productCode: undefined,
+        productCategory: undefined,
+        productCategoryList: undefined,
+        manufacturer: undefined,
+        brand: undefined,
+        productLabel: undefined,
+        licenseExpiryReminder: undefined,
+        productLicenseExpiry: undefined,
+        productQualification: undefined,
+        approvalNumber: undefined,
+        taste: undefined,
+        dosageForm: undefined,
+        supplier: undefined,
+        applicableDepartment: undefined,
+        contraindicationLabel: undefined,
+        shelfLifeReminder: undefined,
+        shelfLife: undefined,
+        purchasePrice: undefined,
+        purchaseUnit: '袋',
+        defaultUsage: undefined,
+        packageUnit: '袋',
+        productSpec: undefined,
+        productSpecValue: undefined,
+        productSpecUnit: 'g',
+        packagePrice: undefined,
+        minUnit: '包',
+        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,
+        status: undefined,
+        putFlag: undefined,
+        outboundNumber: undefined
+    };
+
+    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;
+    }
+
+    /** 查询营养产品信息列表 */
+    const getList = async () => {
+
+        loading.value = true;
+        const res = await listNutrition(queryParams.value);
+        nutritionList.value = res.rows;
+        total.value = res.total;
+        loading.value = false;
+    }
+
+    /** 取消按钮 */
+    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 {
+            queryParams.value.productCategory = undefined;
+        }
+        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);
+                }
+                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);
+                }
+                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 handleFileChange = (file: UploadFile, uploadFiles: UploadFiles) => {
+        fileList.value = uploadFiles;
+    }
+
+    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();
+        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;
+                    }
+                }
+                return null;
+            };
+            return findCategory(categoryOptions.value, id);
+        }).filter(name => name !== null);
+
+        return categoryNames.length > 0 ? categoryNames.join('/') : '--';
+    };
+</script>
+
+<style lang="scss" scoped>
+    .nutrition-dialog {
+        :deep(.el-dialog) {
+            height: 70vh;
+            margin-top: 15vh !important;
+
+            .el-dialog__body {
+                height: calc(100% - 120px);
+                padding: 10px 20px;
+                overflow: hidden;
+            }
+
+            .el-tabs {
+                height: 100%;
+
+                .el-tabs__content {
+                    height: calc(100% - 40px);
+                    overflow: hidden;
+                }
+            }
+
+            .el-scrollbar {
+                height: 100%;
+
+                .el-scrollbar__wrap {
+                    overflow-x: hidden;
+                }
+            }
+
+            .el-form {
+                padding: 20px;
+            }
+        }
+    }
+
+    .dialog-footer {
+        padding: 20px;
+        text-align: right;
+    }
+</style>

+ 308 - 0
src/views/warehouse/productCategory/index.vue

@@ -0,0 +1,308 @@
+<template>
+    <div class="p-2">
+        <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+            <div v-show="showSearch">
+                <el-form ref="queryFormRef" :model="queryParams" :inline="true" class="bg-[#f8f8f9] p-[10px] mb-[10px]">
+                    <el-form-item label="分类名称" prop="categoryName">
+                        <el-input v-model="queryParams.categoryName" placeholder="请输入" clearable style="width: 180px" @keyup.enter="handleQuery" />
+                    </el-form-item>
+                    <el-form-item>
+                        <el-button type="primary" class="ml-2" @click="handleQuery">查询</el-button>
+                        <el-button class="ml-2" @click="resetQuery">重置</el-button>
+                    </el-form-item>
+                </el-form>
+            </div>
+        </transition>
+
+        <el-card>
+            <template #header>
+                <el-row :gutter="10" class="mb-[10px]">
+                    <el-col :span="1.5">
+                        <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+                    </el-col>
+                    <el-col :span="1.5">
+                        <el-button type="primary" plain icon="CaretBottom" @click="handleExpandAll">{{ isExpanded ? '收起' : '展开' }}所有</el-button>
+                    </el-col>
+                </el-row>
+            </template>
+
+            <el-table ref="tableRef" v-loading="loading" :data="categoryTreeData" row-key="categoryId" border :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" class="custom-table">
+                <el-table-column label="分类名称" align="left" prop="categoryName" min-width="180" />
+                <el-table-column label="操作" align="center" width="180">
+                    <template #default="scope">
+                        <!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" class="table-operation-button">编辑</el-button> -->
+                        <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" class="table-operation-button">删除</el-button>
+                    </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" class="mt-[15px]" />
+        </el-card>
+
+        <!-- 添加或修改产品分类对话框 -->
+        <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body :close-on-click-modal="false" destroy-on-close>
+            <el-form ref="categoryFormRef" :model="form" :rules="rules" label-width="100px" class="mt-[20px]">
+                <el-form-item label="上级分类" prop="parentId">
+                    <el-tree-select v-model="form.parentId" :data="categoryOptions" placeholder="请选择" clearable :props="{ 
+                            label: 'categoryName',
+                            value: 'categoryId',
+                            children: 'children'
+                        }" style="width: 100%" />
+                </el-form-item>
+                <el-form-item label="分类名称" prop="categoryName">
+                    <el-input v-model="form.categoryName" placeholder="请输入" />
+                </el-form-item>
+            </el-form>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button @click="cancel">关闭</el-button>
+                    <el-button :loading="buttonLoading" type="primary" @click="submitForm">保存</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="ProductCategory" lang="ts">
+    import { listCategory, getCategory, delCategory, addCategory, updateCategory } from '@/api/warehouse/productCategory/index';
+    import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/warehouse/productCategory/types';
+    import { handleTree } from '@/utils/tree';
+    import { getCurrentInstance, reactive, ref, onMounted, toRefs } from 'vue';
+    import type { FormInstance, ElTable } from 'element-plus';
+    import type { ComponentInternalInstance } from 'vue';
+
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+    const categoryList = ref < CategoryVO[] > ([]);
+    const categoryTreeData = ref < CategoryVO[] > ([]);
+    const loading = ref(false);
+    const showSearch = ref(true);
+    const total = ref(0);
+    const buttonLoading = ref(false);
+    const categoryOptions = ref < CategoryVO[] > ([]);
+
+    const queryFormRef = ref < FormInstance > ();
+    const categoryFormRef = ref < FormInstance > ();
+    const tableRef = ref < InstanceType < typeof ElTable >> ();
+    const isExpanded = ref(false);
+
+    const data = reactive < {
+        form: CategoryForm;
+        queryParams: CategoryQuery & {
+            pageNum: number;
+            pageSize: number;
+        };
+        rules: Record < string,
+        any[] > ;
+        dialog: {
+            visible: boolean;
+            title: string;
+        };
+    } > ({
+        form: {
+            categoryId: undefined,
+            parentId: undefined,
+            categoryName: ''
+        },
+        queryParams: {
+            pageNum: 1,
+            pageSize: 10,
+            categoryName: ''
+        },
+        rules: {
+            categoryName: [{ required: true, message: '分类名称不能为空', trigger: 'blur' }]
+        },
+        dialog: {
+            visible: false,
+            title: ''
+        }
+    });
+
+    const { form, queryParams, rules, dialog } = toRefs(data);
+
+    /** 查询分类列表 */
+    const getList = async () => {
+        loading.value = true;
+        try {
+            const res = await listCategory(queryParams.value);
+            categoryList.value = res.rows;
+            total.value = res.total;
+            // 构建树形数据
+            categoryTreeData.value = handleTree(res.rows, 'categoryId', 'parentId');
+            // 构建选择项数据
+            categoryOptions.value = handleTree(res.rows, 'categoryId', 'parentId');
+        } catch (error) {
+            console.error(error);
+        } finally {
+            loading.value = false;
+        }
+    }
+
+    /** 取消按钮 */
+    const cancel = () => {
+        reset();
+        dialog.value.visible = false;
+    }
+
+    /** 表单重置 */
+    const reset = () => {
+        form.value = {
+            categoryId: undefined,
+            parentId: undefined,
+            categoryName: ''
+        };
+        categoryFormRef.value ?.resetFields();
+    }
+
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        queryParams.value.pageNum = 1;
+        getList();
+    }
+
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        queryFormRef.value ?.resetFields();
+        handleQuery();
+    }
+
+    /** 新增按钮操作 */
+    const handleAdd = () => {
+        reset();
+        dialog.value.visible = true;
+        dialog.value.title = '新增';
+    }
+
+    /** 修改按钮操作 */
+    const handleUpdate = async (row: CategoryVO) => {
+        reset();
+        const id = row.categoryId;
+        const res = await getCategory(id);
+        Object.assign(form.value, res.data);
+        dialog.value.visible = true;
+        dialog.value.title = '修改分类';
+    }
+
+    /** 提交按钮 */
+    const submitForm = async () => {
+        categoryFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                try {
+                    if (form.value.categoryId) {
+                        await updateCategory(form.value);
+                    } else {
+                        await addCategory(form.value);
+                    }
+                    proxy ?.$modal.msgSuccess('操作成功');
+                    dialog.value.visible = false;
+                    await getList();
+                } catch (error) {
+                    console.error(error);
+                } finally {
+                    buttonLoading.value = false;
+                }
+            }
+        });
+    }
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row: CategoryVO) => {
+        const categoryIds = [row.categoryId];
+        proxy ?.$modal.confirm('是否确认删除分类编号为"' + categoryIds + '"的数据项?').then(async () => {
+            try {
+                await delCategory(categoryIds);
+                proxy ?.$modal.msgSuccess('删除成功');
+                await getList();
+            } catch (error) {
+                console.error(error);
+            }
+        });
+    }
+
+    /** 展开/收起所有 */
+    const handleExpandAll = () => {
+        if (!tableRef.value) return;
+
+        const status = !isExpanded.value;
+        isExpanded.value = status;
+
+        categoryTreeData.value.forEach((row) => {
+            tableRef.value ?.toggleRowExpansion(row, status);
+        });
+    };
+
+    // 替换原来的handleCloseAll函数
+    const handleCloseAll = handleExpandAll;
+
+    onMounted(() => {
+        getList();
+    });
+</script>
+
+<style lang="scss" scoped>
+    .custom-table {
+        :deep(.el-table__border) {
+            border-color: #ebeef5;
+        }
+
+        :deep(.el-table__inner-wrapper::before) {
+            background-color: #ebeef5;
+        }
+
+        :deep(.el-table__row) {
+            height: 50px;
+        }
+
+        :deep(.el-table__cell) {
+            padding: 8px 0;
+        }
+
+        :deep(.table-operation-button) {
+            padding: 0 12px;
+            font-size: 14px;
+
+            &.el-button--danger {
+                color: #ff4d4f;
+                margin-left: 16px;
+
+                &:hover {
+                    color: #ff7875;
+                }
+            }
+        }
+    }
+
+    :deep(.el-card) {
+        border-radius: 4px;
+
+        .el-card__header {
+            padding: 12px 20px;
+            border-bottom: 1px solid #ebeef5;
+        }
+    }
+
+    :deep(.el-dialog) {
+        border-radius: 8px;
+
+        .el-dialog__header {
+            margin: 0;
+            padding: 15px 20px;
+            border-bottom: 1px solid #dcdfe6;
+        }
+
+        .el-dialog__title {
+            font-size: 15px;
+            font-weight: 500;
+        }
+
+        .el-dialog__body {
+            padding: 20px;
+        }
+
+        .el-dialog__footer {
+            padding: 15px 20px;
+            border-top: 1px solid #dcdfe6;
+        }
+    }
+</style>

+ 303 - 0
src/views/warehouse/suppliesCategory/index.vue

@@ -0,0 +1,303 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch">
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true" class="bg-[#f8f8f9] p-[10px] mb-[10px]">
+          <el-form-item label="分类名称" prop="categoryName">
+            <el-input v-model="queryParams.categoryName" placeholder="请输入" clearable style="width: 180px" @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" class="ml-2" @click="handleQuery">查询</el-button>
+            <el-button class="ml-2" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </transition>
+
+    <el-card>
+      <template #header>
+        <el-row :gutter="10" class="mb-[10px]">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="CaretBottom" @click="handleExpandAll">{{ isExpanded ? '收起' : '展开' }}所有</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table ref="tableRef" v-loading="loading" :data="categoryTreeData" row-key="categoryId" border :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" class="custom-table">
+        <el-table-column label="耗材分类名称" align="left" prop="categoryName" min-width="180" />
+        <el-table-column label="操作" align="center" width="180">
+          <template #default="scope">
+            <el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" class="table-operation-button">删除</el-button>
+          </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" class="mt-[15px]" />
+    </el-card>
+
+    <!-- 添加或修改耗材分类对话框 -->
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body :close-on-click-modal="false" destroy-on-close>
+      <el-form ref="categoryFormRef" :model="form" :rules="rules" label-width="150px" class="mt-[20px]">
+        <el-form-item label="上级分类" prop="parentId">
+          <el-tree-select v-model="form.parentId" :data="categoryOptions" placeholder="请选择" clearable :props="{ 
+                  label: 'categoryName',
+                  value: 'categoryId',
+                  children: 'children'
+              }" style="width: 100%" />
+        </el-form-item>
+        <el-form-item label="耗材分类名称" prop="categoryName">
+          <el-input v-model="form.categoryName" placeholder="请输入" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="cancel">关闭</el-button>
+          <el-button :loading="buttonLoading" type="primary" @click="submitForm">保存</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="SuppliesCategory" lang="ts">
+import { listSuppliesCategory, getSuppliesCategory, delSuppliesCategory, addSuppliesCategory, updateSuppliesCategory } from '@/api/warehouse/suppliesCategory/index';
+import { CategoryVO, CategoryQuery, CategoryForm } from '@/api/warehouse/suppliesCategory/types';
+import { handleTree } from '@/utils/tree';
+import { getCurrentInstance, reactive, ref, onMounted, toRefs } from 'vue';
+import type { FormInstance, ElTable } from 'element-plus';
+import type { ComponentInternalInstance } from 'vue';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const categoryList = ref<CategoryVO[]>([]);
+const categoryTreeData = ref<CategoryVO[]>([]);
+const loading = ref(false);
+const showSearch = ref(true);
+const total = ref(0);
+const buttonLoading = ref(false);
+const categoryOptions = ref<CategoryVO[]>([]);
+
+const queryFormRef = ref<FormInstance>();
+const categoryFormRef = ref<FormInstance>();
+const tableRef = ref<InstanceType<typeof ElTable>>();
+const isExpanded = ref(false);
+
+const data = reactive<{
+    form: CategoryForm;
+    queryParams: CategoryQuery & {
+        pageNum: number;
+        pageSize: number;
+    };
+    rules: Record<string, any[]>;
+    dialog: {
+        visible: boolean;
+        title: string;
+    };
+}>({
+    form: {
+        categoryId: undefined,
+        parentId: undefined,
+        categoryName: ''
+    },
+    queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        categoryName: ''
+    },
+    rules: {
+        categoryName: [{ required: true, message: '耗材分类名称不能为空', trigger: 'blur' }]
+    },
+    dialog: {
+        visible: false,
+        title: ''
+    }
+});
+
+const { form, queryParams, rules, dialog } = toRefs(data);
+
+/** 查询分类列表 */
+const getList = async () => {
+    loading.value = true;
+    try {
+        const res = await listSuppliesCategory(queryParams.value);
+        categoryList.value = res.rows;
+        total.value = res.total;
+        // 构建树形数据
+        categoryTreeData.value = handleTree(res.rows, 'categoryId', 'parentId');
+        // 构建选择项数据
+        categoryOptions.value = handleTree(res.rows, 'categoryId', 'parentId');
+    } catch (error) {
+        console.error(error);
+    } finally {
+        loading.value = false;
+    }
+}
+
+/** 取消按钮 */
+const cancel = () => {
+    reset();
+    dialog.value.visible = false;
+}
+
+/** 表单重置 */
+const reset = () => {
+    form.value = {
+        categoryId: undefined,
+        parentId: undefined,
+        categoryName: ''
+    };
+    categoryFormRef.value?.resetFields();
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+    queryParams.value.pageNum = 1;
+    getList();
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+    queryFormRef.value?.resetFields();
+    handleQuery();
+}
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+    reset();
+    dialog.value.visible = true;
+    dialog.value.title = '新增';
+}
+
+/** 修改按钮操作 */
+const handleUpdate = async (row: CategoryVO) => {
+    reset();
+    const id = row.categoryId;
+    const res = await getSuppliesCategory(id);
+    Object.assign(form.value, res.data);
+    dialog.value.visible = true;
+    dialog.value.title = '修改分类';
+}
+
+/** 提交按钮 */
+const submitForm = async () => {
+    categoryFormRef.value?.validate(async (valid: boolean) => {
+        if (valid) {
+            buttonLoading.value = true;
+            try {
+                if (form.value.categoryId) {
+                    await updateSuppliesCategory(form.value);
+                } else {
+                    await addSuppliesCategory(form.value);
+                }
+                proxy?.$modal.msgSuccess('操作成功');
+                dialog.value.visible = false;
+                await getList();
+            } catch (error) {
+                console.error(error);
+            } finally {
+                buttonLoading.value = false;
+            }
+        }
+    });
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (row: CategoryVO) => {
+    const categoryIds = [row.categoryId];
+    proxy?.$modal.confirm('是否确认删除分类编号为"' + categoryIds + '"的数据项?').then(async () => {
+        try {
+            await delSuppliesCategory(categoryIds);
+            proxy?.$modal.msgSuccess('删除成功');
+            await getList();
+        } catch (error) {
+            console.error(error);
+        }
+    });
+}
+
+/** 展开/收起所有 */
+const handleExpandAll = () => {
+    if (!tableRef.value) return;
+
+    const status = !isExpanded.value;
+    isExpanded.value = status;
+
+    categoryTreeData.value.forEach((row) => {
+        tableRef.value?.toggleRowExpansion(row, status);
+    });
+};
+
+onMounted(() => {
+    getList();
+});
+</script>
+
+<style lang="scss" scoped>
+    .custom-table {
+        :deep(.el-table__border) {
+            border-color: #ebeef5;
+        }
+
+        :deep(.el-table__inner-wrapper::before) {
+            background-color: #ebeef5;
+        }
+
+        :deep(.el-table__row) {
+            height: 50px;
+        }
+
+        :deep(.el-table__cell) {
+            padding: 8px 0;
+        }
+
+        :deep(.table-operation-button) {
+            padding: 0 12px;
+            font-size: 14px;
+
+            &.el-button--danger {
+                color: #ff4d4f;
+                margin-left: 16px;
+
+                &:hover {
+                    color: #ff7875;
+                }
+            }
+        }
+    }
+
+    :deep(.el-card) {
+        border-radius: 4px;
+
+        .el-card__header {
+            padding: 12px 20px;
+            border-bottom: 1px solid #ebeef5;
+        }
+    }
+
+    :deep(.el-dialog) {
+        border-radius: 8px;
+
+        .el-dialog__header {
+            margin: 0;
+            padding: 15px 20px;
+            border-bottom: 1px solid #dcdfe6;
+        }
+
+        .el-dialog__title {
+            font-size: 15px;
+            font-weight: 500;
+        }
+
+        .el-dialog__body {
+            padding: 20px;
+        }
+
+        .el-dialog__footer {
+            padding: 15px 20px;
+            border-top: 1px solid #dcdfe6;
+        }
+    }
+</style>

+ 873 - 0
src/views/workbench/treatmentUser/index.vue

@@ -0,0 +1,873 @@
+<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">
+                        <el-form-item label="患者类型" prop="type">
+                            <el-select v-model="queryParams.type" clearable>
+                                <el-option v-for="dict in treatment_user_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="科室" prop="doorId">
+                            <el-tree-select v-model="queryParams.doorId" :data="treeData" :props="treeProps" placeholder="请选择" check-strictly node-key="id" @keyup.enter="handleQuery" />
+                        </el-form-item>
+                        <el-form-item label="患者状态" prop="treatmentUserStatus" v-if="showStatusSearch">
+                            <el-select v-model="queryParams.treatmentUserStatus" clearable>
+                                <el-option v-for="dict in treatment_user_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="评估状态" prop="evaluationStatus">
+                            <el-select v-model="queryParams.evaluationStatus" clearable>
+                                <el-option v-for="dict in evaluation_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item prop="searchFlag">
+                            <el-input v-model="queryParams.searchFlag" placeholder="姓名/门诊号/身份证号/医生" clearable @keyup.enter="handleQuery" />
+                        </el-form-item>
+                        <el-form-item>
+                            <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
+                            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:user:add']">添加患者</el-button>
+                        </el-form-item>
+                    </el-form>
+                </el-card>
+            </div>
+        </transition>
+
+        <el-card shadow="never">
+            <div class="status-tabs">
+                <div class="tab-item" :class="{ 'active': activeTab === 'waiting' }" @click="handleTabClick('waiting')">
+                    待诊
+                    <el-badge :value="waitingCount" class="tab-badge" />
+                </div>
+                <div class="tab-item" :class="{ 'active': activeTab === 'treating' }" @click="handleTabClick('treating')">
+                    诊中
+                    <el-badge :value="treatingCount" class="tab-badge" />
+                </div>
+                <div class="tab-item" :class="{ 'active': activeTab === 'treated' }" @click="handleTabClick('treated')">
+                    已诊
+                    <el-badge :value="treatedCount" class="tab-badge" />
+                </div>
+                <div class="tab-item" :class="{ 'active': activeTab === 'reapply' }" @click="handleTabClick('reapply')">
+                    处方重申
+                    <el-badge :value="reapplyCount" class="tab-badge" />
+                </div>
+            </div>
+
+            <div class="patient-cards-container" v-if="userList.length > 0">
+                <el-row :gutter="20">
+                    <el-col v-for="(patient, index) in userList" :key="index" :xs="24" :sm="12" :md="8" :lg="6" :xl="4">
+                        <el-card class="patient-card" shadow="hover" @click="showPatientDetail(patient)">
+                            <div class="patient-status-bar" :class="getStatusBarClass(patient)">
+                                {{ getStatusText(patient) }}
+                            </div>
+                            <div class="patient-info">
+                                <div class="patient-header">
+                                    <div class="patient-name-age">
+                                        <span class="patient-name">{{ patient.treatName }}</span>
+                                        <span class="patient-age">{{ patient.age }}</span>
+                                    </div>
+                                    <span class="gender-icon" :class="patient.sex === '1' ? 'male' : 'female'">
+                                        {{ patient.sex === '1' ? '♂' : '♀' }}
+                                    </span>
+                                </div>
+                                <div class="patient-detail">
+                                    <span class="detail-label">门诊号:</span>
+                                    <span>{{ patient.outpatientNo }}</span>
+                                </div>
+                                <div class="patient-detail">
+                                    <span class="detail-label">科室:</span>
+                                    <span>{{ patient.deptName }}</span>
+                                </div>
+                                <div class="evaluation-info">
+                                    <span class="evaluation-score" v-if="patient.treatmentUserStatus==='4'">营养筛查得分:{{ patient.score }}</span>
+                                    <span class="evaluation-status" :class="patient.evaluationStatus === '1' ? 'evaluated' : 'not-evaluated'">
+                                        {{ patient.evaluationStatus === '1' ? '已评估' : '未评估' }}
+                                    </span>
+                                </div>
+                            </div>
+                        </el-card>
+                    </el-col>
+                </el-row>
+            </div>
+            <div v-else class="empty-state">
+                <img src="@/assets/images/empty.png" alt="暂无数据" />
+                <p>暂无数据</p>
+            </div>
+        </el-card>
+        <!-- 添加或修改【待诊患者】对话框 -->
+        <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
+            <el-form ref="userFormRef" :model="form" :rules="rules" label-width="80px">
+                <el-form-item label="看诊类型" prop="type">
+                    <el-radio-group v-model="form.type">
+                        <el-radio label="1">住院</el-radio>
+                        <el-radio label="0">门诊</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-row :gutter="10">
+                    <el-col :span="12">
+                        <el-form-item label="诊疗卡号" prop="treatNum">
+                            <el-input v-model="form.treatNum" placeholder="系统生成" disabled />
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="门诊号" prop="outpatientNo">
+                            <el-input v-model="form.outpatientNo" placeholder="系统生成" disabled />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-row :gutter="10">
+                    <el-col :span="12">
+                        <el-form-item label="科室" prop="doorId">
+                            <el-tree-select v-model="form.doorId" :data="treeData" :props="treeProps" placeholder="请选择" check-strictly node-key="id" />
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <div v-show="form.type == '1'">
+                    <el-row :gutter="10">
+                        <el-col :span="12">
+                            <el-form-item label="床号" prop="bedNum">
+                                <el-input v-model="form.bedNum" placeholder="请输入" />
+                            </el-form-item>
+                        </el-col>
+                        <el-col :span="12">
+                            <el-form-item label="病区" prop="inpatientWard">
+                                <el-select v-model="form.inpatientWard" placeholder="请选择">
+
+                                </el-select>
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                    <el-row :gutter="10">
+                        <el-col :span="12">
+                            <el-form-item v-if="data.form.type === '1'" label="入院日期" prop="admissionDate" :required="data.form.type === '1'">
+                                <el-date-picker v-model="data.form.admissionDate" type="date" placeholder="请选择" value-format="YYYY-MM-DD" style="width: 100%" />
+                            </el-form-item>
+                        </el-col>
+                    </el-row>
+                </div>
+                <el-row :gutter="10">
+                    <el-col :span="12">
+                        <el-form-item label="姓名" prop="treatName">
+                            <el-input v-model="form.treatName" placeholder="请输入" />
+                        </el-form-item>
+                        <el-form-item label="身份证" prop="idCard">
+                            <el-input v-model="form.idCard" placeholder="请输入" @input="handleIdCardChange" />
+                        </el-form-item>
+                        <el-form-item label="年龄" prop="age">
+                            <el-input v-model="form.age" placeholder="请输入" disabled />
+                        </el-form-item>
+                        <el-form-item label="身高" prop="height">
+                            <el-input v-model="form.height" placeholder="请输入" min="0" oninput="value=value.replace(/[^0-9.]/g,'')" style="width: calc(100% - 40px)">
+                                <template #append>cm</template>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+                    <el-col :span="12">
+                        <el-form-item label="性别" prop="sex">
+                            <el-select v-model="form.sex" placeholder="请选择" clearable>
+                                <el-option v-for="dict in user_sex" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="出生日期" prop="birthday">
+                            <el-input v-model="form.birthday" placeholder="请输入" disabled />
+                        </el-form-item>
+                        <el-form-item label="联系电话" prop="phoneNum">
+                            <el-input v-model="form.phoneNum" placeholder="请输入" />
+                        </el-form-item>
+                        <el-form-item label="体重" prop="weight">
+                            <el-input v-model="form.weight" placeholder="请输入" style="width: calc(100% - 40px)">
+                                <template #append>kg</template>
+                            </el-input>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-form-item label="过敏食物" prop="allergyFoot">
+                    <el-input type="textarea" v-model="form.allergyFoot" placeholder="请输入" maxlength="120" show-word-limit @input="handleTextareaInput" />
+                </el-form-item>
+                <el-form-item label="过敏药物" prop="allergyDrug">
+                    <el-input type="textarea" v-model="form.allergyDrug" placeholder="请输入" maxlength="120" show-word-limit @input="handleTextareaInput" />
+                </el-form-item>
+                <el-row :gutter="10">
+                    <el-col :span="12">
+                        <el-form-item label="体力活动" prop="activity">
+                            <el-select v-model="form.activity" placeholder="请选择" clearable>
+                                <el-option v-for="dict in physical_activity" :key="dict.value" :label="dict.label" :value="dict.value" />
+                            </el-select>
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+            </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 v-model="showDetail" :visible="showDetail" title="查看门诊患者信息" width="900px" append-to-body>
+            <div style="padding: 20px 30px;">
+                <el-row :gutter="24">
+                    
+                    <el-col :span="12">
+                        <div><b>看诊类型:</b>{{ detailData.type === '0' ? '门诊' : '住院' }}</div>
+                        <div><b>诊疗卡号:</b>{{ detailData.treatNum || '--' }}</div>
+                        <div><b>科室:</b>{{ detailData.deptName || '--' }}</div>
+                        <div><b>姓名:</b>{{ detailData.treatName || '--' }}</div>
+                        <div><b>身份证:</b>{{ detailData.idCard || '--' }}</div>
+                        <div><b>年龄:</b>{{ detailData.age || '--' }}</div>
+                        <div><b>身高:</b>{{ detailData.height ? detailData.height + 'cm' : '--' }}</div>
+                        <div><b>BMI:</b>{{ detailData.bmi || '--' }}</div>
+                        <div><b>过敏食物:</b>{{ detailData.allergyFoot || '--' }}</div>
+                        <div><b>过敏药物:</b>{{ detailData.allergyDrug || '--' }}</div>
+                        <div><b>体力活动:</b>{{ getDictLabel(physical_activity.value, detailData.activity) || '--' }}</div>
+                    </el-col>
+                    <el-col :span="12">
+                        <div><b>门诊号:</b>{{ detailData.outpatientNo || '--' }}</div>
+                        <div><b>性别:</b>{{ detailData.sex === '1' ? '男' : detailData.sex === '2' ? '女' : '--' }}</div>
+                        <div><b>出生日期:</b>{{ detailData.birthday || '--' }}</div>
+                        <div><b>联系电话:</b>{{ detailData.phoneNum || '--' }}</div>
+                        <div><b>体重:</b>{{ detailData.weight ? detailData.weight + 'kg' : '--' }}</div>
+                    </el-col>
+                </el-row>
+            </div>
+            <template #footer>
+                <el-button @click="showDetail = false">关闭</el-button>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup name="TreatmentUser" lang="ts">
+    import { listTreatmentUser, getTreatmentUser, delTreatmentUser, addTreatmentUser, updateTreatmentUser } from '@/api/workbench/treatmentUser';
+    import { listDept } from '@/api/system/dept';
+    import { TreatmentUserVo, TreatmentUserForm, TreatmentUserQuery } from '@/api/workbench/treatmentUser/types';
+    import { log } from 'console';
+import { get } from 'http';
+    const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+    const { treatment_user_type, treatment_user_status, evaluation_status, physical_activity, user_sex } = toRefs < any > (proxy ?.useDict('treatment_user_type', 'treatment_user_status', 'evaluation_status', 'physical_activity', 'user_sex'));
+    const userList = ref < TreatmentUserVo[] > ([]);
+    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 treeData = ref([]); // 定义 treeData
+
+    const waitingCount = ref(0);
+    const treatingCount = ref(0);
+    const treatedCount = ref(0);
+    const reapplyCount = ref(0);
+    const showStatusSearch = computed(() => activeTab.value !== 'reapply');
+
+    // 当前选中的标签
+    const activeTab = ref('waiting');
+
+    // 点击标签切换
+    const handleTabClick = (tabType: string) => {
+        activeTab.value = tabType;
+        getList(); // 重新加载数据
+    };
+
+    const queryFormRef = ref < ElFormInstance > ();
+    const userFormRef = ref < ElFormInstance > ();
+
+    const dialog = reactive < DialogOption > ({
+        visible: false,
+        title: ''
+    });
+
+    const treeProps = ref({
+        value: 'deptId', // 对应部门的 deptId
+        label: 'deptName', // 对应部门的 deptName
+        children: 'children' // 保持原有的父子结构
+    });
+
+    const initFormData: TreatmentUserForm = {
+        id: undefined,
+        type: '0',
+        treatNum: undefined,
+        outpatientNo: undefined,
+        doorId: undefined,
+        treatName: undefined,
+        sex: undefined,
+        idCard: undefined,
+        phoneNum: undefined,
+        birthday: undefined,
+        age: undefined,
+        height: undefined,
+        weight: undefined,
+        allergyFoot: undefined,
+        allergyDrug: undefined,
+        activity: undefined,
+    }
+    const data = reactive < PageData < TreatmentUserForm,
+        TreatmentUserQuery >> ({
+            form: { ...initFormData },
+
+            queryParams: {
+                pageNum: 1,
+                pageSize: 10,
+                type: '0',
+                doorId: undefined,
+                treatNum: undefined,
+                searchFlag: undefined,
+                outpatientNo: undefined,
+                evaluationStatus: undefined,
+                treatmentUserStatus: undefined,
+
+                params: {}
+            },
+            // 状态计数(独立 ref)
+
+            rules: {
+                type: [{ required: true, message: '看诊类型为空', trigger: 'blur' }],
+                doorId: [{ required: true, message: '科室不能为空', trigger: 'blur' }],
+                treatName: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
+                sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }],
+                idCard: [{ required: true, message: '身份证不能为空', trigger: 'blur' }],
+                admissionDate: [{
+                    validator: (rule, value, callback) => {
+                        // 只有当 type 为 '1' 时才验证
+                        if (data.form.type === '1' && !value) {
+                            callback(new Error('入院时间不能为空'));
+                        } else {
+                            callback();
+                        }
+                    },
+                    trigger: 'blur'
+                }]
+
+            }
+        });
+
+    const { queryParams, form, rules } = toRefs(data);
+
+
+    /** 查询【待诊患者】列表 */
+    const getList = async () => {
+        loading.value = true;
+        try {
+            const res = await listTreatmentUser(queryParams.value);
+            // 获取部门数据
+            const deptMap = new Map();
+            treeData.value.forEach(dept => {
+                deptMap.set(dept.deptId, dept.deptName);
+                if (dept.children) {
+                    dept.children.forEach(child => {
+                        deptMap.set(child.deptId, child.deptName);
+                    });
+                }
+            });
+            
+            // 为每个患者添加科室名称
+            userList.value = res.rows.map(patient => ({
+                ...patient,
+                deptName: deptMap.get(patient.doorId) || '未知科室'
+            }));
+            total.value = res.total;
+            loading.value = false;
+            waitingCount.value = res.total;
+        } catch (error) {
+            console.error('获取列表失败:', error);
+            loading.value = false;
+        }
+    }
+   const getDeptList = async () => {
+    loading.value = true;
+    try {
+        const res = await listDept({});
+        if (!res.data) {
+            console.warn("部门数据为空");
+            treeData.value = [];
+            return;
+        }
+        
+        // 处理树形数据
+        const processedData = proxy?.handleTree(res.data, 'deptId');
+        if (!processedData) {
+            console.warn("树形数据处理失败");
+            treeData.value = [];
+            return;
+        }
+        
+        treeData.value = processedData;
+        
+    } catch (error) {
+        console.error('获取部门列表失败:', error);
+        treeData.value = [];
+    } finally {
+        loading.value = false;
+    }
+};
+    const getDictLabel = (dictList, value) => {
+        if (!Array.isArray(dictList)) return value || '--';
+        const item = dictList.find(item => item.value === value);
+        return item ? item.label : (value || '--');
+    };
+    const handleTextareaInput = () => {
+        if (form.allergyFoot.length > 120) {
+            form.allergyFoot = form.allergyFoot.slice(0, 120); // 强制截断
+        }
+        if (form.allergyDrug.length > 120) {
+            form.allergyDrug = form.allergyDrug.slice(0, 120); // 强制截断
+        }
+    };
+    const handleIdCardChange = (idCard: string) => {
+        if (!validateIdCard(idCard)) {
+            return;
+        }
+        // 当身份证号长度足够时(18位或15位)
+        if (idCard.length === 18 || idCard.length === 15) {
+            // 提取出生日期
+            let birthdayStr = '';
+            if (idCard.length === 18) {
+                birthdayStr = idCard.substring(6, 14);
+                form.value.birthday = `${birthdayStr.substring(0, 4)}-${birthdayStr.substring(4, 6)}-${birthdayStr.substring(6, 8)}`;
+            } else if (idCard.length === 15) {
+                birthdayStr = '19' + idCard.substring(6, 12);
+                form.value.birthday = `${birthdayStr.substring(0, 4)}-${birthdayStr.substring(4, 6)}-${birthdayStr.substring(6, 8)}`;
+            }
+
+            // 计算年龄
+            if (birthdayStr) {
+                const birthYear = parseInt(birthdayStr.substring(0, 4));
+                const birthMonth = parseInt(birthdayStr.substring(4, 6)) - 1;
+                const birthDay = parseInt(birthdayStr.substring(6, 8));
+
+                const today = new Date();
+                const birthDate = new Date(birthYear, birthMonth, birthDay);
+
+                let age = today.getFullYear() - birthDate.getFullYear();
+                if (today.getMonth() < birthDate.getMonth() || (today.getMonth() === birthDate.getMonth() && today.getDate() < birthDate.getDate())) {
+                    age--;
+                }
+
+                // 设置为"xx岁x月"的格式
+                form.value.age = `${age}岁${today.getMonth() - birthDate.getMonth()}月`;
+            }
+
+            // 根据身份证倒数第二位判断性别(奇数为男,偶数为女)
+            const genderNum = parseInt(idCard.length === 18 ? idCard.charAt(16) : idCard.charAt(14));
+            form.value.sex = (genderNum % 2 === 1 ? '1' : '2').toString();
+        }
+    }
+
+    const validateIdCard = (idCard: string) => {
+        // 18位身份证正则
+        const reg18 = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
+        // 15位身份证正则
+        const reg15 = /^[1-9]\d{5}\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$/;
+
+        return reg18.test(idCard) || reg15.test(idCard);
+    }
+
+    /** 取消按钮 */
+    const cancel = () => {
+        reset();
+        dialog.visible = false;
+    }
+
+    /** 表单重置 */
+    const reset = () => {
+        form.value = { ...initFormData };
+        userFormRef.value ?.resetFields();
+    }
+
+    /** 搜索按钮操作 */
+    const handleQuery = () => {
+        queryParams.value.pageNum = 1;
+        getList();
+    }
+
+    /** 重置按钮操作 */
+    const resetQuery = () => {
+        queryFormRef.value ?.resetFields();
+        handleQuery();
+    }
+
+    /** 多选框选中数据 */
+    const handleSelectionChange = (selection: TreatmentUserVo[]) => {
+        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 ? : TreatmentUserVo) => {
+        reset();
+        const _id = row ?.id || ids.value[0]
+        const res = await getTreatmentUser(_id);
+        Object.assign(form.value, res.data);
+        dialog.visible = true;
+        dialog.title = "修改门诊患者";
+    }
+
+    /** 提交按钮 */
+    const submitForm = () => {
+        userFormRef.value ?.validate(async (valid: boolean) => {
+            if (valid) {
+                buttonLoading.value = true;
+                if (form.value.id) {
+                    await updateTreatmentUser(form.value).finally(() => buttonLoading.value = false);
+                } else {
+                    await addTreatmentUser(form.value).finally(() => buttonLoading.value = false);
+                }
+                proxy ?.$modal.msgSuccess("操作成功");
+                dialog.visible = false;
+                await getList();
+            }
+        });
+    }
+
+    /** 删除按钮操作 */
+    const handleDelete = async (row ? : TreatmentUserVo) => {
+        const _ids = row ?.id || ids.value;
+        await proxy ?.$modal.confirm('是否确认删除门诊患者编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+        await delTreatmentUser(_ids);
+        proxy ?.$modal.msgSuccess("删除成功");
+        await getList();
+    }
+
+    /** 导出按钮操作 */
+    const handleExport = () => {
+        proxy ?.download('workbench/treatmentUser/export', {
+            ...queryParams.value
+        }, `user_${new Date().getTime()}.xlsx`)
+    }
+
+    const getStatusBarClass = (patient) => {
+        if (patient.treatmentUserStatus === '0') {
+            return 'need-intervention'
+        }
+        return 'not-checked';
+    };
+
+    const getStatusText = (patient) => {
+        if (patient.treatmentUserStatus === '0') {
+            return '需进行营养干预'
+        }
+        if (patient.treatmentUserStatus === '1') {
+            return '已过复筛日'
+        }
+        if (patient.treatmentUserStatus === '2') {
+            return '待筛查'
+        }
+        if (patient.treatmentUserStatus === '3') {
+            return '未筛查'
+        }
+        if (patient.treatmentUserStatus === '4') {
+            return '已筛查'
+        }
+        if (patient.treatmentUserStatus === '5') {
+            return '复筛提醒'
+        }
+        if (patient.treatmentUserStatus === '6') {
+            return '今日复筛'
+        }
+        return '';
+    };
+
+    const getAge = (birthday) => {
+        if (!birthday) return 0;
+        const birthDate = new Date(birthday);
+        const today = new Date();
+        let age = today.getFullYear() - birthDate.getFullYear();
+        if (today.getMonth() < birthDate.getMonth() || (today.getMonth() === birthDate.getMonth() && today.getDate() < birthDate.getDate())) {
+            age--;
+        }
+        return age;
+    };
+
+    const getMonths = (birthday) => {
+        if (!birthday) return 0;
+        const birthDate = new Date(birthday);
+        const today = new Date();
+        const months = (today.getFullYear() - birthDate.getFullYear()) * 12 +
+            (today.getMonth() - birthDate.getMonth());
+        return months % 12;
+    };
+    onMounted(() => {
+        getList();
+        getDeptList(); // 初始化时加载部门数据
+    });
+
+    const showDetail = ref(false);
+    const detailData = ref({});
+    const showPatientDetail = async (patient) => {
+        
+        // 这里可以根据需要请求详情接口,或直接用patient
+        detailData.value = { ...patient };
+        showDetail.value = true;
+    };
+
+</script>
+<style scoped>
+    .item {
+        cursor: pointer;
+        padding: 8px 12px;
+        border-radius: 4px;
+        transition: all 0.3s;
+    }
+
+    .item:hover {
+        background-color: #f5f5f5;
+    }
+
+    .active-tab {
+        font-weight: 300;
+        /* 激活标签文字加粗 */
+        border-bottom: 6px solid var(--el-color-primary);
+        padding-bottom: 6px;
+        /* 调整下划线间距 */
+    }
+
+    .active-tab .el-badge__content {
+        background-color: white;
+        color: var(--el-color-primary);
+    }
+
+    .fade-enter-active,
+    .fade-leave-active {
+        transition: opacity 0.3s;
+    }
+
+    .fade-enter-from,
+    .fade-leave-to {
+        opacity: 0;
+    }
+
+    .word-count {
+        text-align: right;
+        font-size: 12px;
+        color: #999;
+        margin-top: 4px;
+    }
+
+    .patient-cards-container {
+        margin-top: 20px;
+    }
+
+    .patient-card {
+        margin-bottom: 20px;
+        border: 1px solid #e4e7ed;
+        transition: all 0.3s;
+        position: relative;
+        overflow: hidden;
+        border-radius: 4px;
+        height: 100%;
+    }
+
+    .patient-card:hover {
+        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    }
+
+    .patient-status-bar {
+        position: absolute;
+        left: 0;
+        top: 0;
+        bottom: 0;
+        width: 32px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        color: white;
+        font-size: 16px;
+        writing-mode: vertical-lr;
+        text-orientation: upright;
+        letter-spacing: 4px;
+        text-align: center;
+        padding: 10px 0;
+    }
+
+    .patient-status-bar.need-intervention {
+        background-color: #ff4949;
+    }
+
+    .patient-status-bar.not-checked {
+        background-color: #409eff;
+    }
+
+    .patient-info {
+        padding: 15px 15px 15px 42px;
+        margin-left: 32px;
+    }
+
+    .patient-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+    }
+
+    .patient-name-age {
+        display: flex;
+        align-items: center;
+        gap: 60px;
+    }
+
+    .patient-name {
+        font-size: 18px;
+        font-weight: bold;
+    }
+
+    .patient-age {
+        font-size: 18px;
+        color: #606266;
+        white-space: nowrap;
+    }
+
+    .gender-icon {
+        font-size: 25px;
+        font-weight:bold;
+    }
+
+    .gender-icon.female {
+        color: #ff4949;
+    }
+
+    .gender-icon.male {
+        color: #409eff;
+    }
+
+    .patient-detail {
+        margin: 8px 0;
+        font-size: 14px;
+        color: #606266;
+    }
+
+    .detail-label {
+        color: #909399;
+        margin-right: 4px;
+        font-size: 16px;
+    }
+
+    .evaluation-info {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 12px;
+        font-size: 16px;
+        position: relative;
+        min-height: 24px;
+    }
+
+    .evaluation-score {
+        flex: 1;
+        font-size: 16px;
+    }
+
+    .evaluation-status {
+        padding: 2px 8px;
+        border-radius: 4px;
+        position: absolute;
+        right: 0;
+        font-size: 16px;
+    }
+
+    .evaluation-status.evaluated {
+        color: #67c23a;
+        background-color: #f0f9eb;
+    }
+
+    .evaluation-status.not-evaluated {
+        color: #909399;
+        background-color: #f4f4f5;
+    }
+
+    .status-text {
+        writing-mode: vertical-lr;
+        text-orientation: mixed;
+        white-space: nowrap;
+        color: #fff;
+        font-size: 14px;
+        letter-spacing: 1px;
+    }
+
+    .search-form {
+        margin-bottom: 20px;
+    }
+
+    .search-form .el-form-item {
+        margin-bottom: 18px;
+        margin-right: 18px;
+    }
+
+    .search-form .el-input,
+    .search-form .el-select,
+    .search-form .el-tree-select {
+        width: 200px;
+    }
+
+    .search-form .el-button {
+        margin-left: 10px;
+    }
+
+    .status-tabs {
+        display: flex;
+        border-bottom: 1px solid #e4e7ed;
+        margin-bottom: 20px;
+        padding: 0 25px;
+    }
+
+    .tab-item {
+        position: relative;
+        padding: 0 20px 16px;
+        font-size: 22px;
+        cursor: pointer;
+        color: #606266;
+        margin-right: 32px;
+    }
+
+    .tab-item.active {
+        color: var(--el-color-primary);
+        font-weight: 500;
+    }
+
+    .tab-item.active::after {
+        content: '';
+        position: absolute;
+        bottom: -1px;
+        left: 0;
+        width: 100%;
+        height: 6px;
+        background-color: var(--el-color-primary);
+        border-radius: 3px 3px 0 0;
+    }
+
+    .tab-badge {
+        position: absolute;
+        top: -8px;
+        right: 0;
+        transform: translateX(50%);
+    }
+
+    .tab-badge :deep(.el-badge__content) {
+        background-color: #ff4949;
+    }
+
+    .empty-state {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        padding: 40px 0;
+        color: #909399;
+    }
+
+    .empty-state img {
+        width: 160px;
+        height: 160px;
+        margin-bottom: 16px;
+    }
+</style>

+ 9 - 2
vite.config.ts

@@ -2,8 +2,10 @@ import { defineConfig, loadEnv } from 'vite';
 import createPlugins from './vite/plugins';
 import autoprefixer from 'autoprefixer'; // css自动添加兼容性前缀
 import path from 'path';
+import ElementPlus from 'unplugin-element-plus/vite'; // 新增导入
 
 export default defineConfig(({ mode, command }) => {
+    
   const env = loadEnv(mode, process.cwd());
   return {
     // 部署生产环境和开发环境下的URL。
@@ -17,7 +19,10 @@ export default defineConfig(({ mode, command }) => {
       extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
     },
     // https://cn.vitejs.dev/config/#resolve-extensions
-    plugins: createPlugins(env, command === 'build'),
+    plugins: [
+      ...createPlugins(env, command === 'build'), // 保留原有插件
+      ElementPlus({ useSource: true }), // 新增 ElementPlus 自动导入样式
+    ],
     server: {
       host: '0.0.0.0',
       port: Number(env.VITE_APP_PORT),
@@ -41,6 +46,7 @@ export default defineConfig(({ mode, command }) => {
       },
       postcss: {
         plugins: [
+      
           // 浏览器兼容性
           autoprefixer(),
           {
@@ -50,7 +56,8 @@ export default defineConfig(({ mode, command }) => {
                 atRule.remove();
               }
             }
-          }
+          },
+          
         ]
       }
     },