Bläddra i källkod

feat(goods): 更新商品API接口并优化协议供货页面

- 修改商品浏览记录列表API路径,移除Page后缀
- 新增采购方案收藏功能API接口
- 重构协议供货页面搜索表单,支持多级商品分类筛选
- 添加商品编号和商品名称搜索字段
- 实现三级商品类别联动选择功能
- 优化价格区间输入和排序功能
- 重构页面样式,提升用户体验
- 移除分页组件依赖,调整数据加载逻辑
- 更新采购计划页面,集成真实API数据
- 添加采购方案类型映射配置
- 实现方案列表加载状态和错误处理
- 优化我的足迹页面数据结构处理
肖路 1 månad sedan
förälder
incheckning
baf0ced598

+ 10 - 1
src/api/goods/index.ts

@@ -55,7 +55,7 @@ export const deleteProductBrowsingHistory = (ids: any) => {
 //查看商品浏览记录列表
 export const browsingHistoryList = (query: any) => {
   return request({
-    url: '/product/myProduct/getProductBrowsingHistoryPage',
+    url: '/product/myProduct/getProductBrowsingHistory',
     method: 'get',
     params: query
   });
@@ -133,3 +133,12 @@ export const getProcurementProgramProductList = (query: any) => {
     params: query
   });
 };
+
+//收藏采购方案
+export function addProcurementProgramCollect(data: any) {
+  return request({
+    url: '/product/myProduct/addProcurementProgramCollect',
+    method: 'post',
+    data: data
+  });
+}

+ 300 - 83
src/views/enterprise/agreementSupply/index.vue

@@ -1,83 +1,131 @@
 <template>
   <div class="page-container">
-    <PageTitle title="协议供货" />
-    <!-- 搜索栏 -->
-    <div class="search-bar">
-      <el-input v-model="queryParams.keyword" placeholder="搜索" style="width: 180px" clearable>
-        <template #prefix
-          ><el-icon><Search /></el-icon
-        ></template>
-      </el-input>
-      <div class="price-range">
-        <el-input v-model="queryParams.minPrice" placeholder="¥ 最高价" style="width: 100px" />
-        <span class="range-separator">—</span>
-        <el-input v-model="queryParams.maxPrice" placeholder="¥ 最低价" style="width: 100px" />
+    <PageTitle title="协议供货商品" />
+    <!-- 搜索表单区 -->
+    <div class="search-form-card">
+      <!-- 第一行:商品编号、商品名称、商品品牌 -->
+      <div class="form-row">
+        <div class="form-item">
+          <span class="form-label">商品编号:</span>
+          <el-input v-model="queryParams.productNo" placeholder="请输入商品编号" clearable style="flex:1" @keyup.enter="handleQuery" />
+        </div>
+        <div class="form-item">
+          <span class="form-label">商品名称:</span>
+          <el-input v-model="queryParams.itemName" placeholder="请输入商品名称" clearable style="flex:1" @keyup.enter="handleQuery" />
+        </div>
       </div>
-      <el-select v-model="queryParams.category" placeholder="商品类别" style="width: 100px" clearable>
-        <el-option v-for="item in categoryList" :key="item.id" :label="item.categoryName" :value="item.id" />
-      </el-select>
-    </div>
-    <!-- 排序栏 -->
-    <div class="sort-bar">
-      <el-select v-model="queryParams.sortType" placeholder="默认排序" style="width: 110px">
-        <el-option label="默认排序" value="default" /><el-option label="销量优先" value="sales" /><el-option label="最新上架" value="newest" />
-      </el-select>
-      <el-select v-model="queryParams.priceSort" placeholder="价格排序" style="width: 110px">
-        <el-option label="价格排序" value="" /><el-option label="价格从低到高" value="asc" /><el-option label="价格从高到低" value="desc" />
-      </el-select>
-    </div>
-    <!-- 商品列表 -->
-    <div class="product-grid">
-      <div v-for="(item, index) in productList" :key="item.id || index" class="product-card">
-        <div class="product-image">
-          <el-image :src="item.productImage" fit="contain">
-            <template #error
-              ><div class="image-placeholder">
-                <el-icon :size="40" color="#ccc"><Picture /></el-icon></div
-            ></template>
-          </el-image>
+      <!-- 第二行:售价区间、商品类别 -->
+      <div class="form-row">
+        <div class="form-item">
+          <span class="form-label">售价区间:</span>
+          <el-input v-model="queryParams.minPrice" placeholder="售价最低" style="width: 110px" />
+          <span class="range-sep">-</span>
+          <el-input v-model="queryParams.maxPrice" placeholder="售价最高" style="width: 110px" />
+        </div>
+        <div class="form-item category-item">
+          <span class="form-label">商品类别:</span>
+          <el-select v-model="queryParams.topCategoryId" placeholder="请选择" clearable @change="handleFirstCategoryChange" style="flex:1">
+            <el-option v-for="item in categoryList1" :key="item.id" :label="item.categoryName" :value="item.id" />
+          </el-select>
+          <el-select v-model="queryParams.middleCategoryId" placeholder="请选择" clearable :disabled="!queryParams.topCategoryId" @change="handleSecondCategoryChange" style="flex:1">
+            <el-option v-for="item in categoryList2" :key="item.id" :label="item.categoryName" :value="item.id" />
+          </el-select>
+          <el-select v-model="queryParams.bottomCategoryId" placeholder="请选择" clearable :disabled="!queryParams.middleCategoryId" style="flex:1">
+            <el-option v-for="item in categoryList3" :key="item.id" :label="item.categoryName" :value="item.id" />
+          </el-select>
         </div>
-        <div class="product-info">
-          <div class="product-name">{{ item.itemName }}</div>
-          <div class="product-price">
-            <span class="price-tag">协议价</span>
-            <span class="current-price">¥{{ formatPrice(item.agreementPrice || item.price) }}</span>
-            <span class="original-price">¥{{ formatPrice(item.marketPrice) }}</span>
-            <div class="add-cart" @click="handleAddCart(item)">
-              <el-icon><Plus /></el-icon>
+      </div>
+      <!-- 第三行:操作按钮 -->
+      <div class="form-actions">
+        <el-button type="primary" @click="handleQuery">查询</el-button>
+        <el-button @click="handleReset">清除选择</el-button>
+      </div>
+    </div>
+
+    <!-- 商品内容区 -->
+    <div class="content-card">
+      <!-- 排序栏 -->
+      <div class="sort-bar">
+        <el-button
+          :class="['sort-btn', { active: queryParams.sortField === '1' }]"
+          size="small"
+          @click="handleSortToggle('1')"
+        >默认排序 <el-icon><Sort /></el-icon></el-button>
+        <el-button
+          :class="['sort-btn', { active: queryParams.sortField === '3' }]"
+          size="small"
+          @click="handleSortToggle('3')"
+        >价格排序 <el-icon><Sort /></el-icon></el-button>
+      </div>
+      <!-- 商品列表 -->
+      <div v-if=" productList.length > 0">
+        <div class="product-grid">
+          <div v-for="(item, index) in productList" :key="item.id || index" class="product-card">
+            <div class="product-image">
+              <el-image :src="item.productImage" fit="contain">
+                <template #error
+                  ><div class="image-placeholder">
+                    <el-icon :size="40" color="#ccc"><Picture /></el-icon></div
+                ></template>
+              </el-image>
+            </div>
+            <div class="product-info">
+              <div class="product-name">{{ item.itemName }}</div>
+              <div class="product-price">
+                <span class="price-tag">协议价</span>
+                <span class="current-price">¥{{ formatPrice(item.agreementPrice || item.price) }}</span>
+                <span class="original-price">¥{{ formatPrice(item.marketPrice) }}</span>
+                <div class="add-cart" @click="handleAddCart(item)">
+                  <el-icon><Plus /></el-icon>
+                </div>
+              </div>
             </div>
           </div>
         </div>
+        <TablePagination
+          v-model:page="queryParams.pageNum"
+          v-model:page-size="queryParams.pageSize"
+          :total="total"
+          @change="loadProductList"
+        />
+      </div>
+      <!-- 空状态 -->
+      <div v-else class="empty-area">
+        <el-icon :size="80" color="#d0d0d0"><Box /></el-icon>
+        <p class="empty-title">未收到任何系统消息</p>
+        <p class="empty-desc">
+          <a href="#" class="empty-link">还不快来建立自己的产品专区~~</a>
+          与我们签订产品协议价格,您将拥有您的专属产品专区,价格更低、服务更优!<br />
+          如需要建立自己专属的协议产品专区请联系您的专属客服【取客服联系方式】或致电400-111-0027。
+        </p>
+        <el-button class="policy-btn">了解协议供货政策</el-button>
       </div>
     </div>
-    <el-empty v-if="productList.length === 0" description="暂无协议供货商品" />
-    <TablePagination
-      v-if="productList.length > 0"
-      v-model:page="queryParams.pageNum"
-      v-model:page-size="queryParams.pageSize"
-      :total="total"
-      @change="handleQuery"
-    />
   </div>
 </template>
 
 <script setup lang="ts">
 import { ref, reactive, onMounted } from 'vue';
-import { Search, Picture, Plus } from '@element-plus/icons-vue';
+import { Picture, Plus, Sort, Box } from '@element-plus/icons-vue';
 import { ElMessage } from 'element-plus';
 import { PageTitle, TablePagination } from '@/components';
-import { getAgreementSupplyProductList } from '@/api/goods/index';
+import { getAgreementSupplyProductList, addProductShoppingCart } from '@/api/goods/index';
 import { getProductCategoryList } from '@/api/home/index';
 
 const queryParams = reactive({
   pageNum: 1,
   pageSize: 15,
-  keyword: '',
+  searchKeyword: '',
+  productNo: '',
+  itemName: '',
+  brand: '',
   minPrice: '',
   maxPrice: '',
-  category: '',
-  sortType: 'default',
-  priceSort: ''
+  topCategoryId: '' as number | string,
+  middleCategoryId: '' as number | string,
+  bottomCategoryId: '' as number | string,
+  sortField: '',
+  sortOrder: ''
 });
 const total = ref(0);
 
@@ -100,32 +148,54 @@ interface CategoryItem {
   [key: string]: any;
 }
 
-const categoryList = ref<CategoryItem[]>([]);
+const categoryList1 = ref<CategoryItem[]>([]);
+const categoryList2 = ref<CategoryItem[]>([]);
+const categoryList3 = ref<CategoryItem[]>([]);
 
-// 加载商品类别列表
+// 加载一级商品类别
 const loadCategoryList = async () => {
   try {
     const res = await getProductCategoryList({ classLevel: 1 });
     if (res.data) {
-      categoryList.value = res.data;
+      categoryList1.value = res.data;
     }
   } catch (error) {
     console.error('获取商品类别失败:', error);
-    ElMessage.error('获取商品类别失败');
+  }
+};
+
+// 一级类别变化:加载二级,清空二三级选中
+const handleFirstCategoryChange = async (val: number | string) => {
+  queryParams.middleCategoryId = '';
+  queryParams.bottomCategoryId = '';
+  categoryList2.value = [];
+  categoryList3.value = [];
+  if (!val) return;
+  try {
+    const res = await getProductCategoryList({ classLevel: 2, parentId: val });
+    if (res.data) categoryList2.value = res.data;
+  } catch (error) {
+    console.error('获取二级类别失败:', error);
+  }
+};
+
+// 二级类别变化:加载三级,清空三级选中
+const handleSecondCategoryChange = async (val: number | string) => {
+  queryParams.bottomCategoryId = '';
+  categoryList3.value = [];
+  if (!val) return;
+  try {
+    const res = await getProductCategoryList({ classLevel: 3, parentId: val });
+    if (res.data) categoryList3.value = res.data;
+  } catch (error) {
+    console.error('获取三级类别失败:', error);
   }
 };
 
 // 加载协议供货商品列表
 const loadProductList = async () => {
   try {
-    const res = await getAgreementSupplyProductList({
-      ...queryParams,
-      // 将价格范围转换为后端需要的格式
-      priceRange:
-        queryParams.minPrice && queryParams.maxPrice
-          ? `${queryParams.minPrice}-${queryParams.maxPrice}`
-          : queryParams.minPrice || queryParams.maxPrice || undefined
-    });
+    const res = await getAgreementSupplyProductList({ ...queryParams });
 
     if (res.rows) {
       productList.value = res.rows;
@@ -143,10 +213,46 @@ const handleQuery = () => {
   loadProductList();
 };
 
+// 重置
+const handleReset = () => {
+  queryParams.searchKeyword = '';
+  queryParams.productNo = '';
+  queryParams.itemName = '';
+  queryParams.brand = '';
+  queryParams.minPrice = '';
+  queryParams.maxPrice = '';
+  queryParams.topCategoryId = '';
+  queryParams.middleCategoryId = '';
+  queryParams.bottomCategoryId = '';
+  queryParams.sortField = '';
+  queryParams.sortOrder = '';
+  categoryList2.value = [];
+  categoryList3.value = [];
+  queryParams.pageNum = 1;
+  loadProductList();
+};
+
+// 排序切换
+const handleSortToggle = (field: string) => {
+  if (queryParams.sortField === field) {
+    queryParams.sortOrder = queryParams.sortOrder === 'Asc' ? 'Desc' : 'Asc';
+  } else {
+    queryParams.sortField = field;
+    queryParams.sortOrder = 'Asc';
+  }
+  queryParams.pageNum = 1;
+  loadProductList();
+};
+
 // 添加购物车
-const handleAddCart = (item: ProductItem) => {
-  console.log('添加到购物车:', item);
-  ElMessage.success('已加入购物车');
+const handleAddCart = async (item: ProductItem) => {
+  try {
+    await addProductShoppingCart({ productId: item.id, productNum: 1 });
+    ElMessage.success('已加入购物车');
+  } catch (error) {
+    console.error('加入购物车失败:', error);
+    ElMessage.error('加入购物车失败');
+  }
 };
 
 // 格式化价格显示
@@ -164,38 +270,103 @@ onMounted(() => {
 </script>
 
 <style scoped lang="scss">
-.search-bar {
-  display: flex;
-  align-items: center;
-  gap: 15px;
-  margin-bottom: 15px;
-  .price-range {
+.page-container {
+  background: #f5f5f5;
+  min-height: 100%;
+  padding-bottom: 20px;
+}
+
+// 搜索表单卡片
+.search-form-card {
+  background: #fff;
+  border-radius: 4px;
+  padding: 20px 24px 16px;
+  margin-bottom: 12px;
+
+  .form-row {
     display: flex;
     align-items: center;
-    gap: 5px;
-    .range-separator {
-      color: #999;
+    gap: 20px;
+    margin-bottom: 16px;
+
+    .form-item {
+      display: flex;
+      align-items: center;
+      flex: 1;
+
+      &.category-item {
+        flex: 2;
+        gap: 8px;
+      }
+
+      .form-label {
+        font-size: 14px;
+        color: #333;
+        white-space: nowrap;
+        min-width: 70px;
+      }
+
+      .range-sep {
+        margin: 0 8px;
+        color: #999;
+      }
     }
   }
+
+  .form-actions {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    padding-top: 4px;
+  }
+}
+
+// 商品内容卡片
+.content-card {
+  background: #fff;
+  border-radius: 4px;
+  padding: 16px 20px;
 }
+
+// 排序栏
 .sort-bar {
   display: flex;
-  gap: 10px;
-  margin-bottom: 20px;
+  gap: 8px;
+  margin-bottom: 16px;
+  padding-bottom: 12px;
+  border-bottom: 1px solid #f0f0f0;
+
+  .sort-btn {
+    border-color: #d9d9d9;
+    color: #555;
+
+    &.active {
+      border-color: #409eff;
+      color: #409eff;
+      background: #ecf5ff;
+    }
+  }
 }
+
+// 商品网格
 .product-grid {
   display: grid;
   grid-template-columns: repeat(5, 1fr);
   gap: 15px;
+  margin-bottom: 16px;
 }
+
 .product-card {
   background: #fff;
+  border: 1px solid #f0f0f0;
   border-radius: 8px;
   overflow: hidden;
   transition: all 0.2s;
+
   &:hover {
     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
   }
+
   .product-image {
     height: 160px;
     background: #f9f9f9;
@@ -203,10 +374,12 @@ onMounted(() => {
     align-items: center;
     justify-content: center;
     padding: 10px;
+
     .el-image {
       width: 100%;
       height: 100%;
     }
+
     .image-placeholder {
       width: 100%;
       height: 100%;
@@ -216,8 +389,10 @@ onMounted(() => {
       background: #f5f5f5;
     }
   }
+
   .product-info {
     padding: 12px;
+
     .product-name {
       font-size: 13px;
       color: #333;
@@ -229,25 +404,30 @@ onMounted(() => {
       -webkit-box-orient: vertical;
       margin-bottom: 8px;
     }
+
     .product-price {
       display: flex;
       align-items: center;
       gap: 5px;
       position: relative;
+
       .price-tag {
         font-size: 12px;
         color: #e60012;
       }
+
       .current-price {
         font-size: 16px;
         font-weight: bold;
         color: #e60012;
       }
+
       .original-price {
         font-size: 12px;
         color: #999;
         text-decoration: line-through;
       }
+
       .add-cart {
         position: absolute;
         right: 0;
@@ -262,6 +442,7 @@ onMounted(() => {
         justify-content: center;
         cursor: pointer;
         transition: all 0.2s;
+
         &:hover {
           background: #e60012;
           color: #fff;
@@ -270,4 +451,40 @@ onMounted(() => {
     }
   }
 }
+
+// 空状态区域
+.empty-area {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 60px 20px;
+
+  .empty-title {
+    font-size: 16px;
+    color: #999;
+    margin: 16px 0 12px;
+  }
+
+  .empty-desc {
+    font-size: 13px;
+    color: #666;
+    text-align: center;
+    line-height: 1.8;
+    margin-bottom: 24px;
+  }
+
+  .empty-link {
+    color: #e60012;
+    text-decoration: none;
+
+    &:hover {
+      text-decoration: underline;
+    }
+  }
+
+  .policy-btn {
+    width: 200px;
+    border-color: #d9d9d9;
+  }
+}
 </style>

+ 30 - 47
src/views/enterprise/myFootprint/index.vue

@@ -18,25 +18,16 @@
       </div>
     </div>
     <el-empty v-if="footprintGroups.length === 0" description="暂无浏览足迹" />
-    <TablePagination
-      v-if="footprintGroups.length > 0"
-      v-model:page="queryParams.pageNum"
-      v-model:page-size="queryParams.pageSize"
-      :total="total"
-      @change="handleQuery"
-    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onMounted } from 'vue';
+import { ref, onMounted } from 'vue';
 import { Delete } from '@element-plus/icons-vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
-import { PageTitle, ProductCard, TablePagination } from '@/components';
+import { PageTitle, ProductCard } from '@/components';
 import { browsingHistoryList, deleteProductBrowsingHistory } from '@/api/goods/index';
 
-const queryParams = reactive({ pageNum: 1, pageSize: 20 });
-const total = ref(0);
 const loading = ref(false);
 const footprintGroups = ref<any[]>([]);
 
@@ -59,42 +50,39 @@ const formatDate = (dateStr: string) => {
   return `${d.getMonth() + 1}月${String(d.getDate()).padStart(2, '0')}日`;
 };
 
-/** 将列表按日期分组 */
-const groupByDate = (list: any[]) => {
-  const map = new Map<string, any[]>();
-  list.forEach((item: any) => {
-    const dateKey = (item.createTime || item.browseTime || '').substring(0, 10);
-    if (!map.has(dateKey)) map.set(dateKey, []);
-    map.get(dateKey)!.push(item);
-  });
-  const groups: any[] = [];
-  map.forEach((products, dateKey) => {
-    groups.push({
-      date: formatDate(dateKey),
-      label: getDateLabel(dateKey),
-      products
-    });
-  });
-  return groups;
-};
-
 /** 获取浏览记录列表 */
 const getFootprintList = () => {
   loading.value = true;
-  browsingHistoryList({ pageNum: queryParams.pageNum, pageSize: queryParams.pageSize })
+  browsingHistoryList({ })
     .then((res: any) => {
       if (res.code == 200) {
-        const list = (res.rows || []).map((item: any) => ({
-          ...item,
-          name: item.itemName || item.productName || item.name || '',
-          image: item.productImage || item.image || '',
-          price: item.price || item.memberPrice || item.minSellingPrice || '',
-          originalPrice: item.marketPrice || item.originalPrice || '',
-          tag: item.tag || '',
-          checked: false
-        }));
-        footprintGroups.value = groupByDate(list);
-        total.value = res.total || 0;
+        // 后端返回的是 Map<String, List<PcProductVo>>,key 是日期字符串(yyyy-MM-dd)
+        const dataMap = res.data || {};
+        const groups: any[] = [];
+        
+        // 按日期降序排序(最新的在前面)
+        const sortedDates = Object.keys(dataMap).sort((a, b) => b.localeCompare(a));
+        
+        sortedDates.forEach((dateKey: string) => {
+          const products = (dataMap[dateKey] || []).map((item: any) => ({
+            ...item,
+            name: item.itemName || item.productName || item.name || '',
+            image: item.productImage || item.image || '',
+            price: item.price || item.memberPrice || item.minSellingPrice || '',
+            originalPrice: item.marketPrice || item.originalPrice || '',
+            tag: item.tag || '',
+            checked: false
+          }));
+          
+          groups.push({
+            dateKey, // 保留原始日期 key,用于删除操作
+            date: formatDate(dateKey),
+            label: getDateLabel(dateKey),
+            products
+          });
+        });
+        
+        footprintGroups.value = groups;
       }
     })
     .finally(() => {
@@ -102,10 +90,6 @@ const getFootprintList = () => {
     });
 };
 
-const handleQuery = () => {
-  getFootprintList();
-};
-
 /** 获取所有选中的商品 */
 const getSelectedItems = () => {
   const selected: any[] = [];
@@ -126,7 +110,6 @@ const handleClearAll = () => {
       deleteProductBrowsingHistory(allIds).then((res: any) => {
         if (res.code == 200) {
           ElMessage.success('已清空所有足迹');
-          queryParams.pageNum = 1;
           getFootprintList();
         }
       });

+ 55 - 16
src/views/enterprise/purchasePlan/index.vue

@@ -4,7 +4,7 @@
     <!-- Tab切换 -->
     <StatusTabs v-model="activeTab" :tabs="tabs" type="pill" />
     <!-- 方案列表 -->
-    <div class="plan-grid">
+    <div v-loading="loading" class="plan-grid">
       <div v-for="(item, index) in planList" :key="index" class="plan-card">
         <div class="plan-image">
           <el-image :src="item.image" fit="cover">
@@ -40,6 +40,14 @@ import { ref, reactive, watch } from 'vue';
 import { Picture, ArrowRight } from '@element-plus/icons-vue';
 import { ElMessage } from 'element-plus';
 import { PageTitle, StatusTabs, TablePagination } from '@/components';
+import { getProcurementProgramProductList } from '@/api/goods/index';
+
+// 采购方案类型映射
+const typeMap: Record<string, string> = {
+  purchase: '1',      // 采购方案
+  exclusive: '2',     // 专属采购方案
+  collection: '3'     // 收藏的采购方案
+};
 
 const activeTab = ref('purchase');
 const tabs = [
@@ -48,23 +56,51 @@ const tabs = [
   { key: 'collection', label: '收藏的采购方案' }
 ];
 const queryParams = reactive({ pageNum: 1, pageSize: 10 });
-const total = ref(500);
+const total = ref(0);
 const planList = ref<any[]>([]);
+const loading = ref(false);
 
-const loadData = () => {
-  if (activeTab.value === 'purchase') {
-    planList.value = [
-      { id: 1, name: '2025中秋福利 企业团购方案', description: '千款好礼·百大品牌·个性定制', image: '' },
-      { id: 2, name: '高效会议 一屏搞定', description: '视频会议大屏解决方案,送货上门,免费安装', image: '' },
-      { id: 3, name: '高效会议 一屏搞定', description: '视频会议大屏解决方案,送货上门,免费安装', image: '' }
-    ];
-    total.value = 500;
-  } else if (activeTab.value === 'exclusive') {
-    planList.value = [{ id: 1, name: '专属定制方案A', description: '根据企业需求定制的专属采购方案', image: '' }];
-    total.value = 1;
-  } else {
-    planList.value = [{ id: 1, name: '收藏的方案', description: '您收藏的采购方案', image: '' }];
-    total.value = 1;
+// 加载数据
+const loadData = async () => {
+  loading.value = true;
+  try {
+    const params = {
+      pageNum: queryParams.pageNum,
+      pageSize: queryParams.pageSize,
+      type: typeMap[activeTab.value]
+    };
+    const res = await getProcurementProgramProductList(params);
+    // 根据实际接口返回结构调整
+    const data = res.data || res;
+    if (data && data.rows) {
+      planList.value = data.rows.map((item: any) => ({
+        id: item.id,
+        name: item.tweetsTitle,
+        description: item.programDescribe || item.subtitle,
+        image: item.coverImage,
+        // 保留原始数据以便详情页使用
+        rawData: item
+      }));
+      total.value = data.total || 0;
+    } else if (Array.isArray(data)) {
+      planList.value = data.map((item: any) => ({
+        id: item.id,
+        name: item.tweetsTitle,
+        description: item.programDescribe || item.subtitle,
+        image: item.coverImage,
+        rawData: item
+      }));
+      total.value = data.length;
+    } else {
+      planList.value = [];
+      total.value = 0;
+    }
+  } catch (error) {
+    ElMessage.error('获取采购方案列表失败');
+    planList.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
   }
 };
 
@@ -76,10 +112,13 @@ watch(
   },
   { immediate: true }
 );
+
 const handleQuery = () => {
   loadData();
 };
+
 const handleDetail = (item: any) => {
+  // 可以跳转到详情页或打开弹窗
   ElMessage.info('查看方案详情:' + item.name);
 };
 </script>