Browse Source

feat(product): 优化商品管理功能

- 修复供应商信息API参数命名错误
- 隐藏商品基础页面批量操作按钮
- 统一毛利率显示格式为两位小数
- 移除商品数量列避免重复计算
- 优化商品池页面表单布局
- 添加品牌选择下拉框支持远程搜索
- 实现供应商选择下拉框功能
- 增加商品分类树形选择组件
- 优化时间格式化处理逻辑
- 添加供应商和品牌数据获取功能
肖路 1 tháng trước cách đây
mục cha
commit
67b227fd53

+ 1 - 1
src/api/customer/supplierInfo/index.ts

@@ -129,7 +129,7 @@ export const getApproveList = (query?: InfoQuery): AxiosPromise<InfoVO[]> => {
 
 /**
  * 根据供应商ID获取人员信息
- * @param supplierId 供应商ID
+ * @param Id 供应商ID
  */
 export const getStaffInfoById = (supplierId: string | number) => {
   return request({

+ 2 - 2
src/api/product/poolLink/types.ts

@@ -248,9 +248,9 @@ export interface PoolLinkQuery extends PageQuery {
   brandName?: string;
 
   /**
-   * 分类ID
+   * 底部分类ID
    */
-  categoryId?: string | number;
+  bottomCategoryId?: string | number;
 
   /**
    * 商品状态:1=已上架,0=下架,2=上架中

+ 3 - 3
src/views/product/base/index.vue

@@ -110,7 +110,7 @@
         <div class="ml-auto flex gap-2">
           <el-button type="primary" icon="Plus" @click="handleAdd">商品新增</el-button>
           <el-button type="warning" icon="Check" @click="handleGoReview">商品审核</el-button>
-          <el-button plain>批量操作</el-button>
+<!--          <el-button plain>批量操作</el-button>-->
           <el-button plain icon="Download" @click="handleExport">导出</el-button>
           <el-button circle icon="Refresh" @click="getList"></el-button>
         </div>
@@ -167,7 +167,7 @@
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.0000' }}%</span>
+                <span>{{ scope.row.tempGrossMargin || '0.00' }}%</span>
               </div>
             </div>
           </template>
@@ -565,7 +565,7 @@ const handleSupply = (row: BaseVO) => {
 /** 停售操作 */
 const handleDiscontinue = async (row: BaseVO) => {
   await proxy?.$modal.confirm('确认停售该商品吗?停售后商品将无法正常售卖。');
-  
+
   try {
     // 调用停售API,将商品类型改为3(停售商品)
     await changeProductType({

+ 1 - 1
src/views/product/base/review.vue

@@ -142,7 +142,7 @@
               </div>
               <div>
                 <span class="text-gray-500">暂估毛利率:</span>
-                <span>{{ scope.row.tempGrossMargin || '0.0000' }}%</span>
+                <span>{{ scope.row.tempGrossMargin || '0.00' }}%</span>
               </div>
             </div>
           </template>

+ 9 - 9
src/views/product/pool/index.vue

@@ -21,14 +21,14 @@
 
 
       <el-table v-loading="loading" border :data="poolList">
-        
+
         <el-table-column label="分类商品池名称" align="center" prop="name" />
         <el-table-column label="产品池类型" align="center" prop="type">
           <template #default="scope">
             {{ getPoolTypeLabel(scope.row.type) }}
           </template>
         </el-table-column>
-        <el-table-column label="商品数量" align="center" prop="productCount" />
+<!--        <el-table-column label="商品数量" align="center" prop="productCount" />-->
         <el-table-column label="创建时间" align="center" prop="createTime" width="180" />
         <el-table-column label="待申请" align="center" prop="waitApplyCount" />
         <el-table-column label="待审核" align="center" prop="waitReviewCount" />
@@ -62,18 +62,18 @@
           </el-select>
         </el-form-item>
         <el-form-item label="状态:" prop="isShow">
-          <el-switch 
-            v-model="form.isShow" 
-            active-value="1" 
+          <el-switch
+            v-model="form.isShow"
+            active-value="1"
             inactive-value="0"
             active-text="启用"
           />
         </el-form-item>
         <el-form-item label="描述:" prop="remark">
-          <el-input 
-            v-model="form.remark" 
-            type="textarea" 
-            placeholder="请输入内容" 
+          <el-input
+            v-model="form.remark"
+            type="textarea"
+            placeholder="请输入内容"
             maxlength="200"
             show-word-limit
             :rows="4"

+ 90 - 18
src/views/product/poolLink/index.vue

@@ -24,7 +24,24 @@
               </el-col>
               <el-col :span="6">
                 <el-form-item label="商品品牌" prop="brandId">
-                  <el-input v-model="queryParams.brandId" placeholder="请选择" clearable />
+                  <el-select
+                    v-model="queryParams.brandId"
+                    placeholder="请输入品牌名称搜索"
+                    filterable
+                    remote
+                    clearable
+                    :remote-method="handleBrandSearch"
+                    :loading="brandLoading"
+                    style="width: 100%"
+                    @keyup.enter="handleQuery"
+                  >
+                    <el-option
+                      v-for="item in brandOptions"
+                      :key="item.id"
+                      :label="item.brandName"
+                      :value="item.id"
+                    />
+                  </el-select>
                 </el-form-item>
               </el-col>
               <el-col :span="6">
@@ -38,25 +55,28 @@
             </el-row>
             <el-row :gutter="20">
               <el-col :span="6">
-                <el-form-item label="商品类别" prop="categoryId">
+                <el-form-item label="商品分类" prop="bottomCategoryId">
                   <el-tree-select
-                    v-model="queryParams.categoryId"
+                    v-model="queryParams.bottomCategoryId"
                     :data="categoryOptions"
-                    :props="{ value: 'id', label: 'label', children: 'children' }"
-                    check-strictly
-                    :render-after-expand="false"
+                    :props="{ value: 'id', label: 'label', children: 'children' } as any"
+                    value-key="id"
+                    placeholder="请选择商品分类"
                     clearable
-                    placeholder="请选择商品类别"
-                  >
-                    <template #default="{ data }">
-                      <span>{{ getCategoryFullPath(data.id) }}</span>
-                    </template>
-                  </el-tree-select>
+                    check-strictly
+                  />
                 </el-form-item>
               </el-col>
               <el-col :span="6">
                 <el-form-item label="创建供应商" prop="supplier">
-                  <el-input v-model="queryParams.supplier" placeholder="请选择创建供应商" clearable />
+                  <el-select v-model="queryParams.supplier" placeholder="请选择创建供应商" clearable filterable>
+                    <el-option
+                      v-for="item in supplierOptions"
+                      :key="item.id"
+                      :label="item.enterpriseName || item.shortName"
+                      :value="item.id"
+                    />
+                  </el-select>
                 </el-form-item>
               </el-col>
               <el-col :span="6">
@@ -156,7 +176,11 @@
           </template>
         </el-table-column>
         <el-table-column label="入池时间" align="center" prop="createTime" width="120" />
-        <el-table-column label="创建供应商" align="center" prop="supplier" width="100" />
+        <el-table-column label="创建供应商" align="center" width="100">
+          <template #default="scope">
+            <span>{{ getSupplierName(scope.row.supplier) }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" align="center" width="120" fixed="right">
           <template #default="scope">
             <div class="flex flex-col gap-1">
@@ -337,6 +361,10 @@ import { categoryTree, listBase } from '@/api/product/base';
 import { BaseVO, BaseQuery } from '@/api/product/base/types';
 import { listPoolLink, batchAddProducts, BatchAddProductData, editPrice, editStock, delPoolLink, PoolLinkForm } from '@/api/product/poolLink';
 import { PoolLinkQuery, PoolLinkVO } from '@/api/product/poolLink/types';
+import { listInfo } from '@/api/customer/supplierInfo';
+import { InfoVO } from '@/api/customer/supplierInfo/types';
+import { listBrand } from '@/api/product/brand';
+import { BrandVO } from '@/api/product/brand/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const router = useRouter();
@@ -357,13 +385,17 @@ const queryParams = ref({
   itemName: undefined,
   brandId: undefined,
   productStatus: undefined,
-  categoryId: undefined,
+  bottomCategoryId: undefined,
   supplier: undefined,
   dateRange: undefined,
 });
 
 const categoryOptions = ref<any[]>([]);
 const categoryMap = ref<Map<string | number, any>>(new Map());
+const supplierOptions = ref<InfoVO[]>([]); // 供应商选项
+const brandOptions = ref<BrandVO[]>([]); // 品牌选项
+const brandLoading = ref(false); // 品牌加载状态
+let brandSearchTimer: ReturnType<typeof setTimeout> | null = null; // 品牌搜索防抖定时器
 
 // 添加商品对话框
 const addProductDialog = reactive({
@@ -403,6 +435,44 @@ const getCategoryTree = async () => {
   }
 };
 
+/** 获取供应商列表 */
+const getSupplierList = async () => {
+  try {
+    const res = await listInfo();
+    supplierOptions.value = res.data || res.rows|| [];
+  } catch (error) {
+    console.error('获取供应商列表失败:', error);
+  }
+};
+
+/** 获取供应商名称 */
+const getSupplierName = (supplierId: string | number | undefined): string => {
+  if (!supplierId) return '-';
+  const supplier = supplierOptions.value.find(item => item.id === supplierId);
+  return supplier?.enterpriseName || supplier?.shortName || '-';
+};
+
+/** 加载品牌选项(默认100条) */
+const loadBrandOptions = async (keyword?: string) => {
+  brandLoading.value = true;
+  try {
+    const res = await listBrand({ pageNum: 1, pageSize: 100, brandName: keyword });
+    brandOptions.value = res.rows || [];
+  } catch (error) {
+    console.error('加载品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 品牌远程搜索(防抖) */
+const handleBrandSearch = (query: string) => {
+  if (brandSearchTimer) clearTimeout(brandSearchTimer);
+  brandSearchTimer = setTimeout(() => {
+    loadBrandOptions(query || undefined);
+  }, 300);
+};
+
 /** 构建分类映射 */
 const buildCategoryMap = (categories: any[], parentPath = '') => {
   categories.forEach(category => {
@@ -431,7 +501,7 @@ const getList = async () => {
       productNo: queryParams.value.productNo,
       itemName: queryParams.value.itemName,
       brandId: queryParams.value.brandId,
-      categoryId: queryParams.value.categoryId,
+      bottomCategoryId: queryParams.value.bottomCategoryId,
       productStatus: queryParams.value.productStatus,
       supplier: queryParams.value.supplier
     };
@@ -439,8 +509,8 @@ const getList = async () => {
     // 处理日期范围
     if (queryParams.value.dateRange && queryParams.value.dateRange.length === 2) {
       query.params = {
-        beginCreateTime: queryParams.value.dateRange[0],
-        endCreateTime: queryParams.value.dateRange[1]
+        beginCreateTime: proxy?.parseTime(queryParams.value.dateRange[0], '{y}-{m}-{d} {h}:{i}:{s}') || queryParams.value.dateRange[0],
+        endCreateTime: proxy?.parseTime(queryParams.value.dateRange[1], '{y}-{m}-{d} {h}:{i}:{s}') || queryParams.value.dateRange[1]
       };
     }
 
@@ -741,7 +811,9 @@ const handleRemoveProduct = async (row: PoolLinkVO) => {
 
 onMounted(() => {
   getCategoryTree();
+  getSupplierList();
   getList();
+  loadBrandOptions();
 });
 </script>