Explorar el Código

feat(product): 实现商品品牌选择器优化和游标分页功能

- 将商品品牌选择器从el-select替换为el-select-v2,提升性能和用户体验
- 实现游标分页功能,支持上一页下一页双向翻页操作
- 添加品牌选项格式化计算属性,限制每次加载500条数据
- 优化品牌加载逻辑,实现懒加载和loading状态显示
- 更新商品审核状态的显示值和数据库字段类型
- 调整商品列表页面的查询参数和分页组件配置
- 修复商品品牌查询字段从brandId改为brandName
- 移除登录页面的租户选择功能(暂时注释)
肖路 hace 3 meses
padre
commit
d5071e5731

+ 26 - 15
src/api/product/base/types.ts

@@ -284,27 +284,27 @@ export interface BaseForm extends BaseEntity {
   /**
    * 是否自营(1=是,0=否)
    */
-  isSelf?: string;
+  isSelf?: number;
 
   /**
    * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
    */
-  productReviewStatus?: string;
+  productReviewStatus?: number;
 
   /**
    * 首页推荐:1=推荐,0=不推荐
    */
-  homeRecommended?: string;
+  homeRecommended?: number;
 
   /**
    * 分类推荐:1=推荐,0=不推荐
    */
-  categoryRecommendation?: string;
+  categoryRecommendation?: number;
 
   /**
    * 购物车推荐:1=推荐,0=不推荐
    */
-  cartRecommendation?: string;
+  cartRecommendation?: number;
 
   /**
    * 推荐产品顺序
@@ -314,12 +314,12 @@ export interface BaseForm extends BaseEntity {
   /**
    * 是否热门:1=是,0=否
    */
-  isPopular?: string;
+  isPopular?: number;
 
   /**
    * 是否新品:1=是,0=否
    */
-  isNew?: string;
+  isNew?: number;
 
   /**
    * 商品状态:1=上架,0=下架等
@@ -555,6 +555,11 @@ export interface BaseForm extends BaseEntity {
 
 export interface BaseQuery extends PageQuery {
 
+  /**
+   * 搜索文本(商品名称/商品编号)
+   */
+  searchText?: string;
+
   /**
    * 产品编号
    */
@@ -570,6 +575,11 @@ export interface BaseQuery extends PageQuery {
    */
   brandId?: string | number;
 
+  /**
+   * 商品品牌名称
+   */
+  brandName?: string;
+
   /**
    * 顶级分类id
    */
@@ -598,27 +608,27 @@ export interface BaseQuery extends PageQuery {
   /**
    * 是否自营(1=是,0=否)
    */
-  isSelf?: string;
+  isSelf?: number;
 
   /**
    * 产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回
    */
-  productReviewStatus?: string;
+  productReviewStatus?: number;
 
   /**
    * 首页推荐:1=推荐,0=不推荐
    */
-  homeRecommended?: string;
+  homeRecommended?: number;
 
   /**
    * 分类推荐:1=推荐,0=不推荐
    */
-  categoryRecommendation?: string;
+  categoryRecommendation?: number;
 
   /**
    * 购物车推荐:1=推荐,0=不推荐
    */
-  cartRecommendation?: string;
+  cartRecommendation?: number;
 
   /**
    * 推荐产品顺序
@@ -628,17 +638,17 @@ export interface BaseQuery extends PageQuery {
   /**
    * 是否热门:1=是,0=否
    */
-  isPopular?: string;
+  isPopular?: number;
 
   /**
    * 是否新品:1=是,0=否
    */
-  isNew?: string;
+  isNew?: number;
 
   /**
    * 商品状态:1=上架,0=下架等
    */
-  productStatus?: string | number;
+  productStatus?: number;
 
   /**
    * 平台标识
@@ -670,6 +680,7 @@ export interface BaseQuery extends PageQuery {
    */
   projectOrg?: string;
 
+
     /**
      * 日期范围参数
      */

+ 74 - 3
src/components/Pagination/index.vue

@@ -1,6 +1,33 @@
 <template>
   <div :class="{ hidden: hidden }" class="pagination-container">
+    <!-- 游标分页模式 -->
+    <div v-if="cursorMode" class="cursor-pagination">
+      <el-button
+        :disabled="currentPage === 1"
+        @click="handlePrevPage"
+      >
+        上一页
+      </el-button>
+      <span class="page-info">第 {{ currentPage }} 页</span>
+      <el-button
+        :disabled="!hasMore"
+        @click="handleNextPage"
+      >
+        下一页
+      </el-button>
+      <el-select v-model="pageSize" @change="handleSizeChange" style="width: 100px" class="ml-2">
+        <el-option
+          v-for="size in pageSizes"
+          :key="size"
+          :label="`${size}条/页`"
+          :value="size"
+        />
+      </el-select>
+    </div>
+
+    <!-- 传统分页模式 -->
     <el-pagination
+      v-else
       v-model:current-page="currentPage"
       v-model:page-size="pageSize"
       :background="background"
@@ -22,6 +49,7 @@ const props = defineProps({
   total: propTypes.number,
   page: propTypes.number.def(1),
   limit: propTypes.number.def(20),
+  way: propTypes.number.def(1),
   pageSizes: { type: Array<number>, default: () => [10, 20, 30, 50] },
   // 移动端页码按钮的数量端默认值5
   pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
@@ -29,10 +57,14 @@ const props = defineProps({
   background: propTypes.bool.def(true),
   autoScroll: propTypes.bool.def(true),
   hidden: propTypes.bool.def(false),
-  float: propTypes.string.def('right')
+  float: propTypes.string.def('right'),
+  // 游标分页模式
+  cursorMode: propTypes.bool.def(false),
+  // 是否还有更多数据(游标分页使用)
+  hasMore: propTypes.bool.def(true)
 });
 
-const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
+const emit = defineEmits(['update:page', 'update:limit', 'update:way', 'pagination']);
 const currentPage = computed({
   get() {
     return props.page;
@@ -50,7 +82,7 @@ const pageSize = computed({
   }
 });
 function handleSizeChange(val: number) {
-  if (currentPage.value * val > props.total) {
+  if (!props.cursorMode && currentPage.value * val > props.total) {
     currentPage.value = 1;
   }
   emit('pagination', { page: currentPage.value, limit: val });
@@ -64,6 +96,28 @@ function handleCurrentChange(val: number) {
     scrollTo(0, 800);
   }
 }
+// 游标分页:下一页
+function handleNextPage() {
+  if (props.hasMore) {
+    currentPage.value += 1;
+    emit('update:way', 1);
+    emit('pagination', { page: currentPage.value, limit: pageSize.value, way: 1 });
+    if (props.autoScroll) {
+      scrollTo(0, 800);
+    }
+  }
+}
+// 游标分页:上一页
+function handlePrevPage() {
+  if (currentPage.value > 1) {
+    currentPage.value -= 1;
+    emit('update:way', 0);
+    emit('pagination', { page: currentPage.value, limit: pageSize.value, way: 0 });
+    if (props.autoScroll) {
+      scrollTo(0, 800);
+    }
+  }
+}
 </script>
 
 <style lang="scss" scoped>
@@ -71,6 +125,23 @@ function handleCurrentChange(val: number) {
   .el-pagination {
     float: v-bind(float);
   }
+
+  .cursor-pagination {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 16px;
+    float: v-bind(float);
+
+    .page-info {
+      font-size: 14px;
+      color: #606266;
+    }
+
+    .ml-2 {
+      margin-left: 8px;
+    }
+  }
 }
 .pagination-container.hidden {
   display: none;

+ 15 - 0
src/types/global.d.ts

@@ -87,6 +87,21 @@ declare global {
   declare interface PageQuery {
     pageNum: number;
     pageSize: number;
+
+    /**
+     * 游标分页:上一页使用的第一个记录ID(用于向上翻页)
+     */
+    firstSeenId?: string | number;
+
+    /**
+     * 游标分页:上一页使用的最后一个记录ID(用于向下翻页)
+     */
+    lastSeenId?: string | number;
+
+    /**
+     * 翻页方向:0=上一页,1=下一页(用于游标分页)
+     */
+    way?: number;
   }
   declare interface LayoutSetting {
     /**

+ 6 - 6
src/views/login.vue

@@ -5,12 +5,12 @@
         <h3 class="title">{{ title }}</h3>
         <lang-select />
       </div>
-      <el-form-item v-if="tenantEnabled" prop="tenantId">
-        <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">
-          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>
-          <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
-        </el-select>
-      </el-form-item>
+<!--      <el-form-item v-if="tenantEnabled" prop="tenantId">-->
+<!--        <el-select v-model="loginForm.tenantId" filterable :placeholder="proxy.$t('login.selectPlaceholder')" style="width: 100%">-->
+<!--          <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"></el-option>-->
+<!--          <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
       <el-form-item prop="username">
         <el-input v-model="loginForm.username" type="text" size="large" auto-complete="off" :placeholder="proxy.$t('login.username')">
           <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>

+ 36 - 18
src/views/product/base/add.vue

@@ -245,14 +245,16 @@
               <!-- 商品品牌 -->
                <el-col :span="12">
                 <el-form-item label="商品品牌:" prop="brandId" required>
-                  <el-select v-model="productForm.brandId" placeholder="请选择商品品牌" clearable class="w-full">
-                    <el-option
-                      v-for="option in brandOptions"
-                      :key="option.id"
-                      :label="option.brandName"
-                      :value="option.id"
-                    />
-                  </el-select>
+                  <el-select-v2
+                    v-model="productForm.brandId"
+                    :options="brandOptionsFormatted"
+                    placeholder="请选择商品品牌"
+                    clearable
+                    filterable
+                    class="w-full"
+                    :loading="brandLoading"
+                    @visible-change="handleBrandVisibleChange"
+                  />
                 </el-form-item>
                </el-col>
 
@@ -931,14 +933,14 @@ const productForm = reactive<BaseForm>({
   bottomCategoryId: undefined,
   unitId: undefined,
   productImage: undefined,
-  isSelf: '0',
-  productReviewStatus: '0',
-  homeRecommended: '0',
-  categoryRecommendation: '0',
-  cartRecommendation: '0',
+  isSelf: 0,
+  productReviewStatus: 0,
+  homeRecommended: 0,
+  categoryRecommendation: 0,
+  cartRecommendation: 0,
   recommendedProductOrder: 0,
-  isPopular: '0',
-  isNew: '0',
+  isPopular: 0,
+  isNew: 0,
   productStatus: '0',
   remark: undefined,
   a10ProductName: undefined,
@@ -990,6 +992,13 @@ const productRules = {
 // 分类和品牌选项
 const categoryOptions = ref<categoryTreeVO[]>([]);
 const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+const brandOptionsFormatted = computed(() => {
+  return brandOptions.value.slice(0, 500).map(item => ({
+    label: item.brandName,
+    value: item.id
+  }));
+});
 
 // 商品属性列表
 const attributesList = ref<AttributesVO[]>([]);
@@ -1223,10 +1232,11 @@ const getCategoryTree = async () => {
   }
 };
 
-// 获取品牌列表
+// 获取品牌列表(实时请求,每次只加载500条)
 const getBrandList = async () => {
   try {
-    const res = await brandList();
+    brandLoading.value = true;
+    const res = await brandList({ pageNum: 1, pageSize: 500 });
     brandOptions.value = res.data || [];
     // 如果是新增模式且有选项,设置第一个为默认值
     if (!route.params.id && brandOptions.value.length > 0 && !productForm.brandId) {
@@ -1234,6 +1244,15 @@ const getBrandList = async () => {
     }
   } catch (error) {
     console.error('获取品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+// 处理品牌下拉框显示/隐藏
+const handleBrandVisibleChange = (visible: boolean) => {
+  if (visible && brandOptions.value.length === 0) {
+    getBrandList();
   }
 };
 
@@ -1400,7 +1419,6 @@ const loadProductDetail = async () => {
 
 onMounted(async () => {
   await getCategoryTree();
-  await getBrandList();
   await getUnitOptions();
   await getAfterSalesOptions();
   await getServiceGuaranteeOptions();

+ 194 - 142
src/views/product/base/index.vue

@@ -12,24 +12,17 @@
               </el-col>
               <el-col :span="6">
                 <el-form-item label="商品名称" prop="itemName">
-                   <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品品牌" prop="brandId">
-                  <el-select v-model="queryParams.brandId" placeholder="请选择商品品牌" clearable>
-                    <el-option 
-                      v-for="brand in brandOptions" 
-                      :key="brand.id" 
-                      :label="brand.brandName" 
-                      :value="brand.id" 
-                    />
-                  </el-select>
+                <el-form-item label="商品品牌" prop="brandName">
+                  <el-input v-model="queryParams.brandName" placeholder="请输入商品品牌" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
               </el-col>
               <el-col :span="6">
                 <el-form-item label="商品来源" prop="purchaseNature">
-                   <el-input v-model="queryParams.itemName" placeholder="请输入商品来源" clearable @keyup.enter="handleQuery" />
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品来源" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
               </el-col>
             </el-row>
@@ -58,19 +51,18 @@
               <el-col :span="6">
                 <el-form-item label="审核状态" prop="productReviewStatus">
                   <el-select v-model="queryParams.productReviewStatus" placeholder="请选择" clearable>
-                    <el-option label="待采购审核" :value="0" />
-                    <el-option label="审核通过" :value="1" />
-                   
-                    <el-option label="驳回" :value="2" />
-                     <el-option label="待营销审核" :value="3" />
+                    <el-option label="待采购审核" value="0" />
+                    <el-option label="审核通过" value="1" />
+                    <el-option label="驳回" value="2" />
+                    <el-option label="待营销审核" value="3" />
                   </el-select>
                 </el-form-item>
               </el-col>
               <el-col :span="6">
                 <el-form-item label="上下架状态" prop="productStatus">
                   <el-select v-model="queryParams.productStatus" placeholder="请选择" clearable>
-                    <el-option label="上架" :value="1" />
-                    <el-option label="下架" :value="0" />
+                    <el-option label="上架" value="1" />
+                    <el-option label="下架" value="0" />
                   </el-select>
                 </el-form-item>
               </el-col>
@@ -90,8 +82,14 @@
     <el-card shadow="never" class="mb-[10px]">
       <div class="flex items-center text-sm text-gray-600">
         <span>商品总/已配置数量: </span>
-        <span class="text-blue-600 mx-1">总=<span class="text-red-600">{{ statistics.total }}</span>条,</span>
-        <span>外/已配置数量<span class="text-red-600">{{ statistics.configured }}</span>条,</span>
+        <span class="text-blue-600 mx-1"
+          >总=<span class="text-red-600">{{ statistics.total }}</span
+          >条,</span
+        >
+        <span
+          >外/已配置数量<span class="text-red-600">{{ statistics.configured }}</span
+          >条,</span
+        >
         <span>【上架/总数({{ statistics.onShelf }}/{{ statistics.total }})】</span>
         <span class="mx-2">,审核状态({{ statistics.reviewStatus }}),上架状态({{ statistics.shelfStatus }})</span>
         <div class="ml-auto flex gap-2">
@@ -105,7 +103,6 @@
     </el-card>
 
     <el-card shadow="never">
-
       <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
         <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
@@ -115,14 +112,14 @@
         </el-table-column>
         <el-table-column label="商品图片" align="center" prop="productImage" width="100">
           <template #default="scope">
-            <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
           </template>
         </el-table-column>
         <el-table-column label="商品信息" align="center" width="250" show-overflow-tooltip>
           <template #default="scope">
             <div class="text-left">
               <div>{{ scope.row.itemName }}</div>
-              <div class="text-gray-500" style="font-size: 12px;">品牌: {{ scope.row.brandName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">品牌: {{ scope.row.brandName || '-' }}</div>
             </div>
           </template>
         </el-table-column>
@@ -130,7 +127,7 @@
         <el-table-column label="单位" align="center" prop="unitName" width="80" />
         <el-table-column label="SKU价格" align="center" width="180">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">市场价:</span>
                 <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
@@ -148,7 +145,7 @@
         </el-table-column>
         <el-table-column label="成本情况" align="center" width="150">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">采购价:</span>
                 <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
@@ -167,57 +164,57 @@
         </el-table-column>
         <el-table-column label="是否自营" align="center" width="100">
           <template #default="scope">
-            <el-tag v-if="scope.row.isSelf === '1'" type="success">是</el-tag>
-            <el-tag v-else-if="scope.row.isSelf === '0'" type="info">否</el-tag>
+            <el-tag v-if="scope.row.isSelf === 1" type="success">是</el-tag>
+            <el-tag v-else-if="scope.row.isSelf === 0" type="info">否</el-tag>
             <span v-else>-</span>
           </template>
         </el-table-column>
         <el-table-column label="审核状态" align="center" prop="productReviewStatus" width="100">
           <template #default="scope">
-            <span v-if="scope.row.productReviewStatus === '0'">待提交</span>
-            <span v-else-if="scope.row.productReviewStatus === '1'">审核</span>
-            <span v-else-if="scope.row.productReviewStatus === '2'">审核通过</span>
-            <span v-else-if="scope.row.productReviewStatus === '3'">审核驳回</span>
+            <span v-if="scope.row.productReviewStatus === 0">待采购审核</span>
+            <span v-else-if="scope.row.productReviewStatus === 1">审核通过</span>
+            <span v-else-if="scope.row.productReviewStatus === 2">驳回</span>
+            <span v-else-if="scope.row.productReviewStatus === 3">待营销审核</span>
             <span v-else>-</span>
           </template>
         </el-table-column>
         <el-table-column label="上下架状态" align="center" prop="productStatus" width="120">
           <template #default="scope">
-            <el-tag v-if="scope.row.productStatus === '1'" type="success">上架</el-tag>
-            <el-tag v-else-if="scope.row.productStatus === '0'" type="warning">下架</el-tag>
+            <el-tag v-if="scope.row.productStatus === 1" type="success">上架</el-tag>
+            <el-tag v-else-if="scope.row.productStatus === 0" type="warning">下架</el-tag>
             <el-tag v-else type="info">未知</el-tag>
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" width="200" fixed="right">
           <template #default="scope">
             <!-- 待审核状态:只显示编辑 -->
-            <div v-if="scope.row.productReviewStatus !== '2'" class="flex gap-1 justify-center">
+            <div v-if="scope.row.productReviewStatus !== 2" class="flex gap-1 justify-center">
               <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
             </div>
-            
+
             <!-- 审核通过 -->
-            <div v-else-if="scope.row.productReviewStatus === '2'" class="flex flex-col gap-1">
+            <div v-else-if="scope.row.productReviewStatus === 2" class="flex flex-col gap-1">
               <!-- 下架状态:编辑、上架、停售、修改库存 -->
-              <div v-if="scope.row.productStatus === '0'" class="flex gap-1 justify-center">
+              <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">
                 <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
                 <el-link type="success" :underline="false" @click="handleShelf(scope.row)">上架</el-link>
                 <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
               </div>
-              <div v-if="scope.row.productStatus === '0'" class="flex gap-1 justify-center">
+              <div v-if="scope.row.productStatus === 0" class="flex gap-1 justify-center">
                 <el-link type="primary" :underline="false" @click="handleSupply(scope.row)">修改库存</el-link>
               </div>
-              
+
               <!-- 上架状态:编辑、下架、停售、修改库存 -->
-              <div v-else-if="scope.row.productStatus === '1'" class="flex gap-1 justify-center">
+              <div v-else-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">
                 <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
                 <el-link type="warning" :underline="false" @click="handleShelf(scope.row)">下架</el-link>
                 <el-link type="danger" :underline="false" @click="handleDiscontinue(scope.row)">停售</el-link>
               </div>
-              <div v-else-if="scope.row.productStatus === '1'" class="flex gap-1 justify-center">
+              <div v-else-if="scope.row.productStatus === 1" class="flex gap-1 justify-center">
                 <el-link type="primary" :underline="false" @click="handleSupply(scope.row)">修改库存</el-link>
               </div>
             </div>
-            
+
             <!-- 其他状态(待提交、审核驳回等):显示编辑 -->
             <div v-else class="flex gap-1 justify-center">
               <el-link type="primary" :underline="false" @click="handleUpdate(scope.row)">编辑</el-link>
@@ -226,7 +223,16 @@
         </el-table-column>
       </el-table>
 
-      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="cursorQueryParams.pageNum"
+        v-model:limit="cursorQueryParams.pageSize"
+        v-model:way="cursorQueryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
+      />
     </el-card>
   </div>
 </template>
@@ -249,8 +255,10 @@ const ids = ref<Array<string | number>>([]);
 const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
-const brandOptions = ref<BrandVO[]>([]);
 const categoryOptions = ref<categoryTreeVO[]>([]);
+const hasMore = ref(true); // 是否还有更多数据
+// 页面历史记录,存储每页的第一个id和最后一个id,用于支持双向翻页
+const pageHistory = ref([]);
 
 // 统计信息
 const statistics = ref({
@@ -288,16 +296,16 @@ const initFormData: BaseForm = {
   isPopular: undefined,
   isNew: undefined,
   productStatus: undefined,
-  remark: undefined,
-}
+  remark: undefined
+};
 const data = reactive<PageData<BaseForm, BaseQuery>>({
-  form: {...initFormData},
+  form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
     productNo: undefined,
     itemName: undefined,
-    brandId: undefined,
+    brandName: undefined,
     productTag: undefined,
     purchaseNature: undefined,
     supplierType: undefined,
@@ -306,143 +314,194 @@ const data = reactive<PageData<BaseForm, BaseQuery>>({
     topCategoryId: undefined,
     mediumCategoryId: undefined,
     bottomCategoryId: undefined,
+    isSelf: undefined,
+    productReviewStatus: undefined,
     productStatus: undefined,
-    params: {
-    }
+    params: {}
   },
   rules: {
-    productNo: [
-      { required: true, message: "产品编号不能为空", trigger: "blur" }
-    ],
-    itemName: [
-      { required: true, message: "项目名称不能为空", trigger: "blur" }
-    ],
-    brandId: [
-      { required: true, message: "品牌id不能为空", trigger: "blur" }
-    ],
-    topCategoryId: [
-      { required: true, message: "顶级分类id不能为空", trigger: "blur" }
-    ],
-    mediumCategoryId: [
-      { required: true, message: "中级分类id不能为空", trigger: "blur" }
-    ],
-    bottomCategoryId: [
-      { required: true, message: "底层分类id不能为空", trigger: "blur" }
-    ],
-    unitId: [
-      { required: true, message: "单位id不能为空", trigger: "blur" }
-    ],
-    productImage: [
-      { required: true, message: "产品图片URL不能为空", trigger: "blur" }
-    ],
-    productReviewStatus: [
-      { required: true, message: "产品审核状态 0=待提交,1=待审核,2=审核通过,3=审核驳回不能为空", trigger: "change" }
-    ],
-    homeRecommended: [
-      { required: true, message: "首页推荐:1=推荐,0=不推荐不能为空", trigger: "blur" }
-    ],
-    categoryRecommendation: [
-      { required: true, message: "分类推荐:1=推荐,0=不推荐不能为空", trigger: "blur" }
-    ],
-    cartRecommendation: [
-      { required: true, message: "购物车推荐:1=推荐,0=不推荐不能为空", trigger: "blur" }
-    ],
-    recommendedProductOrder: [
-      { required: true, message: "推荐产品顺序不能为空", trigger: "blur" }
-    ],
-    isPopular: [
-      { required: true, message: "是否热门:1=是,0=否不能为空", trigger: "blur" }
-    ],
-    isNew: [
-      { required: true, message: "是否新品:1=是,0=否不能为空", trigger: "blur" }
-    ],
-    remark: [
-      { required: true, message: "备注不能为空", trigger: "blur" }
-    ],
+    productNo: [{ required: true, message: '产品编号不能为空', trigger: 'blur' }],
+    itemName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
+    brandId: [{ required: true, message: '品牌id不能为空', trigger: 'blur' }],
+    topCategoryId: [{ required: true, message: '顶级分类id不能为空', trigger: 'blur' }],
+    mediumCategoryId: [{ required: true, message: '中级分类id不能为空', trigger: 'blur' }],
+    bottomCategoryId: [{ required: true, message: '底层分类id不能为空', trigger: 'blur' }],
+    unitId: [{ required: true, message: '单位id不能为空', trigger: 'blur' }],
+    productImage: [{ required: true, message: '产品图片URL不能为空', trigger: 'blur' }],
+    productReviewStatus: [{ required: true, message: '产品审核状态 0=待采购审核,1=审核通过,2=驳回,3=待营销审核不能为空', trigger: 'change' }],
+    homeRecommended: [{ required: true, message: '首页推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    categoryRecommendation: [{ required: true, message: '分类推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    cartRecommendation: [{ required: true, message: '购物车推荐:1=推荐,0=不推荐不能为空', trigger: 'blur' }],
+    recommendedProductOrder: [{ required: true, message: '推荐产品顺序不能为空', trigger: 'blur' }],
+    isPopular: [{ required: true, message: '是否热门:1=是,0=否不能为空', trigger: 'blur' }],
+    isNew: [{ required: true, message: '是否新品:1=是,0=否不能为空', trigger: 'blur' }],
+    remark: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
   }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
+// 游标分页查询参数
+const cursorQueryParams = ref<BaseQuery>({
+  pageNum: 1,
+  pageSize: 10,
+  way: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandName: undefined,
+  purchaseNature: undefined,
+  bottomCategoryId: undefined,
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  productStatus: undefined,
+  lastSeenId: undefined // 游标分页的lastSeenId
+});
+
 /** 查询产品基础信息列表 */
 const getList = async () => {
   loading.value = true;
-  const res = await listBase(queryParams.value);
-  baseList.value = res.rows;
-  total.value = res.total;
-  
-  // 更新统计信息
-  statistics.value.total = res.total || 0;
-  statistics.value.configured = res.rows?.filter((item: any) => item.isConfigured)?.length || 0;
-  statistics.value.onShelf = res.rows?.filter((item: any) => item.productStatus === '1')?.length || 0;
-  
-  loading.value = false;
-}
+  try {
+    const params = { ...cursorQueryParams.value };
+    const currentPageNum = cursorQueryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (cursorQueryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBase(params);
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === cursorQueryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+
+    total.value = res.total || 0;
+
+    // 更新统计信息
+    statistics.value.total = res.total || 0;
+    statistics.value.configured = res.rows?.filter((item: any) => item.isConfigured)?.length || 0;
+    statistics.value.onShelf = res.rows?.filter((item: any) => item.productStatus === '1')?.length || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
 
 /** 取消按钮 */
 const cancel = () => {
   reset();
   dialog.visible = false;
-}
+};
 
 /** 表单重置 */
 const reset = () => {
-  form.value = {...initFormData};
+  form.value = { ...initFormData };
   baseFormRef.value?.resetFields();
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  queryParams.value.pageNum = 1;
+  // 同步查询参数到游标分页参数
+  cursorQueryParams.value = {
+    ...cursorQueryParams.value,
+    pageNum: 1,
+    productNo: queryParams.value.productNo,
+    itemName: queryParams.value.itemName,
+    brandName: queryParams.value.brandName,
+    bottomCategoryId: queryParams.value.bottomCategoryId,
+    isSelf: queryParams.value.isSelf,
+    productReviewStatus: queryParams.value.productReviewStatus,
+    productStatus: queryParams.value.productStatus,
+    lastSeenId: undefined
+  };
+  pageHistory.value = []; // 重置页面历史
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  cursorQueryParams.value.lastSeenId = undefined;
+  pageHistory.value = []; // 重置页面历史
   handleQuery();
-}
+};
 
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: BaseVO[]) => {
-  ids.value = selection.map(item => item.id);
+  ids.value = selection.map((item) => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 新增按钮操作 */
 const handleAdd = () => {
   router.push('/product/base/add');
-}
+};
 
 /** 修改按钮操作 */
 const handleUpdate = async (row?: BaseVO) => {
   const _id = row?.id || ids.value[0];
   router.push(`/product/base/edit/${_id}`);
-}
-
+};
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: BaseVO) => {
   const _ids = row?.id || ids.value;
-  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
+  await proxy?.$modal.confirm('是否确认删除产品基础信息编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
   await delBase(_ids);
-  proxy?.$modal.msgSuccess("删除成功");
+  proxy?.$modal.msgSuccess('删除成功');
   await getList();
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('product/base/export', {
-    ...queryParams.value
-  }, `base_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'product/base/export',
+    {
+      ...queryParams.value
+    },
+    `base_${new Date().getTime()}.xlsx`
+  );
+};
 
 /** 查看商品详情 */
 const handleView = (row: BaseVO) => {
   console.log('查看商品', row);
   // TODO: 实现查看详情逻辑
-}
+};
 
 /** 上下架操作 */
 const handleShelf = async (row: BaseVO) => {
@@ -451,19 +510,19 @@ const handleShelf = async (row: BaseVO) => {
   // TODO: 调用上下架API
   proxy?.$modal.msgSuccess(`${action}成功`);
   await getList();
-}
+};
 
 /** 价格设置 */
 const handlePrice = (row: BaseVO) => {
   console.log('设置价格', row);
   // TODO: 打开价格设置对话框
-}
+};
 
 /** 供货存管理 */
 const handleSupply = (row: BaseVO) => {
   console.log('供货存管理', row);
   // TODO: 打开供货存管理对话框
-}
+};
 
 /** 停售操作 */
 const handleDiscontinue = async (row: BaseVO) => {
@@ -471,33 +530,26 @@ const handleDiscontinue = async (row: BaseVO) => {
   // TODO: 调用停售API
   proxy?.$modal.msgSuccess('停售成功');
   await getList();
-}
+};
 
 /** 跳转到商品审核页面 */
 const handleGoReview = () => {
   router.push({
     path: '/product/base/review',
     query: {
-      productReviewStatus: '1' // 默认显示待审核的商品
+      productReviewStatus: 1 // 默认显示待审核的商品
     }
   });
-}
-
-/** 查询品牌列表 */
-const getBrandList = async () => {
-  const res = await brandList();
-  brandOptions.value = res.data || [];
-}
+};
 
 /** 查询分类树 */
 const getCategoryTree = async () => {
   const res = await categoryTree();
   categoryOptions.value = res.data || [];
-}
+};
 
 onMounted(() => {
   getList();
-  getBrandList();
   getCategoryTree();
 });
 </script>

+ 164 - 79
src/views/product/base/review.vue

@@ -7,8 +7,13 @@
           <el-form ref="queryFormRef" :model="queryParams" label-width="100px">
             <el-row :gutter="20">
               <el-col :span="6">
-                <el-form-item label="输入搜索" prop="searchText">
-                  <el-input v-model="queryParams.searchText" placeholder="商品名称/商品编号" clearable @keyup.enter="handleQuery" />
+                <el-form-item label="商品编号" prop="productNo">
+                  <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable @keyup.enter="handleQuery" />
+                </el-form-item>
+              </el-col>
+              <el-col :span="6">
+                <el-form-item label="商品名称" prop="itemName">
+                  <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable @keyup.enter="handleQuery" />
                 </el-form-item>
               </el-col>
               <el-col :span="6">
@@ -25,15 +30,16 @@
                 </el-form-item>
               </el-col>
               <el-col :span="6">
-                <el-form-item label="商品品牌" prop="brandId">
-                  <el-select v-model="queryParams.brandId" placeholder="请选择商品品牌" clearable filterable>
-                    <el-option 
-                      v-for="brand in brandOptions" 
-                      :key="brand.id" 
-                      :label="brand.brandName" 
-                      :value="brand.id" 
-                    />
-                  </el-select>
+                <el-form-item label="商品品牌" prop="brandName">
+                  <el-select-v2
+                    v-model="queryParams.brandName"
+                    :options="brandOptionsFormatted"
+                    placeholder="请选择商品品牌"
+                    clearable
+                    filterable
+                    :loading="brandLoading"
+                    @visible-change="handleBrandVisibleChange"
+                  />
                 </el-form-item>
               </el-col>
               <el-col :span="6">
@@ -63,9 +69,9 @@
 
       <el-table v-loading="loading" border :data="baseList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="商品图片" align="center" prop="productImageUrl" width="100" fixed="left">
+        <el-table-column label="商品图片" align="center" prop="productImage" width="100" fixed="left">
           <template #default="scope">
-            <image-preview :src="scope.row.productImageUrl" :width="60" :height="60"/>
+            <image-preview :src="scope.row.productImage" :width="60" :height="60" />
           </template>
         </el-table-column>
         <el-table-column label="商品编号" align="center" prop="productNo" width="120" fixed="left">
@@ -77,13 +83,13 @@
           <template #default="scope">
             <div class="text-left">
               <div>{{ scope.row.itemName }}</div>
-              <div class="text-gray-500" style="font-size: 12px;">品牌: {{ scope.row.brandName || '-' }}</div>
+              <div class="text-gray-500" style="font-size: 12px">品牌: {{ scope.row.brandName || '-' }}</div>
             </div>
           </template>
         </el-table-column>
         <el-table-column label="基本情况" align="center" width="180">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">商品分类:</span>
                 <span>{{ scope.row.categoryName || '-' }}</span>
@@ -97,7 +103,7 @@
         </el-table-column>
         <el-table-column label="SKU价格" align="center" width="180">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">市场价:</span>
                 <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
@@ -115,7 +121,7 @@
         </el-table-column>
         <el-table-column label="成本预算" align="center" width="150">
           <template #default="scope">
-            <div class="text-left" style="font-size: 12px;">
+            <div class="text-left" style="font-size: 12px">
               <div>
                 <span class="text-gray-500">采购价:</span>
                 <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
@@ -127,17 +133,17 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="提报需求" align="center" width="100">
+        <el-table-column label="商品来源" align="center" width="100">
           <template #default="scope">
             <span>{{ scope.row.dataSource || '-' }}</span>
           </template>
         </el-table-column>
         <el-table-column label="商品状态" align="center" width="100">
           <template #default="scope">
-            <el-tag v-if="scope.row.productReviewStatus === '0'" type="info">待提交</el-tag>
-            <el-tag v-else-if="scope.row.productReviewStatus === '1'" type="warning">审核</el-tag>
-            <el-tag v-else-if="scope.row.productReviewStatus === '2'" type="success">审核通过</el-tag>
-            <el-tag v-else-if="scope.row.productReviewStatus === '3'" type="danger">审核驳回</el-tag>
+            <el-tag v-if="scope.row.productReviewStatus === 0" type="info">待采购审核</el-tag>
+            <el-tag v-else-if="scope.row.productReviewStatus === 1" type="warning">审核通过</el-tag>
+            <el-tag v-else-if="scope.row.productReviewStatus === 2" type="success">驳回</el-tag>
+            <el-tag v-else-if="scope.row.productReviewStatus === 3" type="danger">待营销审核</el-tag>
             <span v-else>-</span>
           </template>
         </el-table-column>
@@ -145,7 +151,7 @@
           <template #default="scope">
             <div class="flex flex-col gap-1">
               <!-- 根据审核状态显示不同按钮 -->
-              <template v-if="scope.row.productReviewStatus === '1'">
+              <template v-if="scope.row.productReviewStatus === 1">
                 <!-- 待审核 -->
                 <div class="flex gap-1 justify-center">
                   <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">编辑</el-link>
@@ -153,7 +159,7 @@
                   <el-link type="danger" :underline="false" @click="handleReject(scope.row)">驳回</el-link>
                 </div>
               </template>
-              <template v-else-if="scope.row.productReviewStatus === '3'">
+              <template v-else-if="scope.row.productReviewStatus === 3">
                 <!-- 审核驳回 -->
                 <div class="flex gap-1 justify-center">
                   <el-link type="primary" :underline="false" @click="handleEdit(scope.row)">编辑</el-link>
@@ -171,12 +177,15 @@
         </el-table-column>
       </el-table>
 
-      <pagination 
-        v-show="total > 0" 
-        :total="total" 
-        v-model:page="queryParams.pageNum" 
-        v-model:limit="queryParams.pageSize" 
-        @pagination="getList" 
+      <!-- 游标分页控制 -->
+      <pagination
+        v-show="baseList.length > 0"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        v-model:way="queryParams.way"
+        :cursor-mode="true"
+        :has-more="hasMore"
+        @pagination="getList"
       />
     </el-card>
 
@@ -196,12 +205,7 @@
           </el-radio-group>
         </el-form-item>
         <el-form-item label="审核意见" prop="reviewRemark">
-          <el-input 
-            v-model="reviewForm.reviewRemark" 
-            type="textarea" 
-            :rows="4" 
-            placeholder="请输入审核意见"
-          />
+          <el-input v-model="reviewForm.reviewRemark" type="textarea" :rows="4" placeholder="请输入审核意见" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -233,7 +237,16 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 const brandOptions = ref<BrandVO[]>([]);
+const brandLoading = ref(false);
+const brandOptionsFormatted = computed(() => {
+  return brandOptions.value.slice(0, 500).map((item) => ({
+    label: item.brandName,
+    value: item.brandName // review.vue使用brandName作为value
+  }));
+});
 const categoryOptions = ref<categoryTreeVO[]>([]);
+const hasMore = ref(true); // 是否还有更多数据
+const pageHistory = ref([]);
 
 const queryFormRef = ref<ElFormInstance>();
 const reviewFormRef = ref<ElFormInstance>();
@@ -255,83 +268,142 @@ const reviewForm = ref<any>({
 
 // 审核表单验证规则
 const reviewRules = ref({
-  reviewStatus: [
-    { required: true, message: "请选择审核结果", trigger: "change" }
-  ],
-  reviewRemark: [
-    { required: true, message: "请输入审核意见", trigger: "blur" }
-  ]
+  reviewStatus: [{ required: true, message: '请选择审核结果', trigger: 'change' }],
+  reviewRemark: [{ required: true, message: '请输入审核意见', trigger: 'blur' }]
 });
 
 const queryParams = ref<BaseQuery>({
   pageNum: 1,
   pageSize: 10,
-  searchText: undefined,
+  way: undefined,
+  productNo: undefined,
+  itemName: undefined,
+  brandName: undefined,
+  purchaseNature: undefined,
   bottomCategoryId: undefined,
-  brandId: undefined,
-  productReviewStatus: '1' // 默认查询待审核状态
+  isSelf: undefined,
+  productReviewStatus: undefined,
+  productStatus: undefined,
+  lastSeenId: undefined // 游标分页的lastSeenId
 });
 
+
 /** 查询商品列表 */
 const getList = async () => {
   loading.value = true;
-  const res = await listBase(queryParams.value);
-  baseList.value = res.rows;
-  total.value = res.total;
-  loading.value = false;
-}
+  try {
+    const params = { ...queryParams.value };
+    const currentPageNum = queryParams.value.pageNum;
+
+    // 第一页不需要游标参数
+    if (currentPageNum === 1) {
+      delete params.lastSeenId;
+      delete params.way;
+    } else {
+      // way参数:0=上一页,1=下一页
+      if (queryParams.value.way === 0) {
+        // 上一页:使用目标页(即当前显示页)的firstId
+        const nextPageHistory = pageHistory.value[currentPageNum];
+        if (nextPageHistory) {
+          params.firstSeenId = nextPageHistory.firstId;
+          params.way = 0;
+        }
+      } else {
+        // 下一页:使用前一页的lastId作为lastSeenId
+        const prevPageHistory = pageHistory.value[currentPageNum - 1];
+        if (prevPageHistory) {
+          params.lastSeenId = prevPageHistory.lastId;
+          params.way = 1;
+        }
+      }
+    }
+
+    const res = await listBase(params);
+    baseList.value = res.rows || [];
+
+    // 判断是否还有更多数据
+    hasMore.value = baseList.value.length === queryParams.value.pageSize;
+
+    // 记录当前页的第一个id和最后一个id
+    if (baseList.value.length > 0) {
+      const firstItem = baseList.value[0];
+      const lastItem = baseList.value[baseList.value.length - 1];
+      //如果长度小于currentPageNum则创建
+
+      if (pageHistory.value.length <= currentPageNum) {
+        pageHistory.value[currentPageNum] = {
+          firstId: firstItem.id,
+          lastId: lastItem.id
+        };
+      }
+    }
+    total.value = res.total || 0;
+  } catch (error) {
+    console.error('获取列表失败:', error);
+  } finally {
+    loading.value = false;
+  }
+};
 
 /** 初始化路由参数 */
 const initRouteParams = () => {
   // 从路由参数中获取筛选条件
   if (route.query.productReviewStatus) {
-    queryParams.value.productReviewStatus = route.query.productReviewStatus as string;
+    queryParams.value.productReviewStatus = Number(route.query.productReviewStatus);
   }
-  if (route.query.brandId) {
-    queryParams.value.brandId = route.query.brandId as string;
+  if (route.query.brandName) {
+    queryParams.value.brandName = route.query.brandName as string;
   }
   if (route.query.bottomCategoryId) {
     queryParams.value.bottomCategoryId = route.query.bottomCategoryId as string;
   }
-}
+};
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.value.pageNum = 1;
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = [0]; // 重置页面历史
   getList();
-}
+};
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
   // 重置后仍然保持待审核状态
-  queryParams.value.productReviewStatus = '1';
+  queryParams.value.productReviewStatus = 1;
+  queryParams.value.lastSeenId = undefined;
+  pageHistory.value = [0]; // 重置页面历史
   handleQuery();
-}
+};
 
 /** 多选框选中数据 */
 const handleSelectionChange = (selection: BaseVO[]) => {
-  ids.value = selection.map(item => item.id);
+  ids.value = selection.map((item) => item.id);
   single.value = selection.length != 1;
   multiple.value = !selection.length;
-}
+};
 
 /** 导出按钮操作 */
 const handleExport = () => {
-  proxy?.download('product/base/export', {
-    ...queryParams.value
-  }, `base_review_${new Date().getTime()}.xlsx`)
-}
+  proxy?.download(
+    'product/base/export',
+    {
+      ...queryParams.value
+    },
+    `base_review_${new Date().getTime()}.xlsx`
+  );
+};
 
 /** 查看商品详情 */
 const handleView = (row: BaseVO) => {
   router.push(`/product/base/detail/${row.id}`);
-}
+};
 
 /** 编辑商品 */
 const handleEdit = (row: BaseVO) => {
   router.push(`/product/base/edit/${row.id}`);
-}
+};
 
 /** 审核商品 */
 const handleReview = (row: BaseVO) => {
@@ -344,7 +416,7 @@ const handleReview = (row: BaseVO) => {
     reviewStatus: 2,
     reviewRemark: ''
   };
-}
+};
 
 /** 驳回商品 */
 const handleReject = (row: BaseVO) => {
@@ -357,48 +429,61 @@ const handleReject = (row: BaseVO) => {
     reviewStatus: 3,
     reviewRemark: ''
   };
-}
+};
 
 /** 重新提交 */
 const handleReSubmit = async (row: BaseVO) => {
   await proxy?.$modal.confirm('确认重新提交该商品进行审核吗?');
   const data: BaseForm = {
     id: row.id,
-    productReviewStatus: '1' // 设置为待审核状态
+    productReviewStatus: 1 // 设置为待审核状态
   };
   await updateBase(data);
-  proxy?.$modal.msgSuccess("重新提交成功");
+  proxy?.$modal.msgSuccess('重新提交成功');
   await getList();
-}
+};
 
 /** 提交审核 */
 const submitReview = async () => {
   await reviewFormRef.value?.validate();
   const data: BaseForm = {
     id: reviewForm.value.id,
-    productReviewStatus: String(reviewForm.value.reviewStatus),
+    productReviewStatus: Number(reviewForm.value.reviewStatus),
     remark: reviewForm.value.reviewRemark
   };
   await updateBase(data);
-  proxy?.$modal.msgSuccess(reviewForm.value.reviewStatus === 2 ? "审核通过" : "审核驳回");
+  proxy?.$modal.msgSuccess(reviewForm.value.reviewStatus === 2 ? '审核通过' : '审核驳回');
   reviewDialog.visible = false;
   await getList();
-}
+};
 
-/** 查询品牌列表 */
+/** 查询品牌列表(实时请求,每次只加载500条) */
 const getBrandList = async () => {
-  const res = await brandList();
-  brandOptions.value = res.data || [];
-}
+  try {
+    brandLoading.value = true;
+    const res = await brandList({ pageNum: 1, pageSize: 500 });
+    brandOptions.value = res.data || [];
+  } catch (error) {
+    console.error('获取品牌列表失败:', error);
+  } finally {
+    brandLoading.value = false;
+  }
+};
+
+/** 处理品牌下拉框显示/隐藏 */
+const handleBrandVisibleChange = (visible: boolean) => {
+  if (visible && brandOptions.value.length === 0) {
+    getBrandList();
+  }
+};
 
 /** 查询分类树 */
 const getCategoryTree = async () => {
   const res = await categoryTree();
   categoryOptions.value = res.data || [];
-}
+};
 
 onMounted(() => {
-  getBrandList();
   getCategoryTree();
   initRouteParams();
   getList();