瀏覽代碼

12-19-zl-前端

林小张 4 天之前
父節點
當前提交
9aee319c38

+ 38 - 0
src/api/product/base.ts

@@ -0,0 +1,38 @@
+import request from '@/utils/request';
+
+const baseUrl = '/product/base';
+
+// 查询商品列表
+export function listProduct(params: any) {
+  return request.get(baseUrl + '/list', { params });
+}
+
+// 获取商品详情
+export function getProduct(id: number | string) {
+  return request.get(`${baseUrl}/${id}`);
+}
+
+// 新增商品
+export function addProduct(data: any) {
+  return request.post(baseUrl, data);
+}
+
+// 修改商品
+export function updateProduct(data: any) {
+  return request.put(baseUrl, data);
+}
+
+// 删除商品
+export function delProduct(id: number | string) {
+  return request.delete(`${baseUrl}/${id}`);
+}
+
+// 获取分类树
+export function getCategoryTree(params?: any) {
+  return request.get(baseUrl + '/categoryTree', { params });
+}
+
+// 获取品牌列表
+export function getBrandList(params?: any) {
+  return request.get(baseUrl + '/brandList', { params });
+}

+ 28 - 0
src/api/product/brand.ts

@@ -0,0 +1,28 @@
+import request from '@/utils/request';
+
+const baseUrl = '/product/brand';
+
+// 查询品牌列表
+export function listBrand(params: any) {
+  return request.get(baseUrl + '/list', { params });
+}
+
+// 获取品牌详情
+export function getBrand(id: number | string) {
+  return request.get(`${baseUrl}/${id}`);
+}
+
+// 新增品牌
+export function addBrand(data: any) {
+  return request.post(baseUrl, data);
+}
+
+// 修改品牌
+export function updateBrand(data: any) {
+  return request.put(baseUrl, data);
+}
+
+// 删除品牌
+export function delBrand(id: number | string) {
+  return request.delete(`${baseUrl}/${id}`);
+}

+ 47 - 0
src/api/product/recommend.ts

@@ -0,0 +1,47 @@
+import request from '@/utils/request';
+
+// 推荐位配置
+const recommendUrl = '/product/recommend';
+
+// 查询推荐位列表
+export function listRecommend(params: any) {
+  return request.get(recommendUrl + '/list', { params });
+}
+
+// 获取推荐位详情
+export function getRecommend(id: number | string) {
+  return request.get(`${recommendUrl}/${id}`);
+}
+
+// 新增推荐位
+export function addRecommend(data: any) {
+  return request.post(recommendUrl, data);
+}
+
+// 修改推荐位
+export function updateRecommend(data: any) {
+  return request.put(recommendUrl, data);
+}
+
+// 删除推荐位
+export function delRecommend(id: number | string) {
+  return request.delete(`${recommendUrl}/${id}`);
+}
+
+// 推荐关联
+const linkUrl = '/product/recommendLink';
+
+// 查询推荐关联列表
+export function listRecommendLink(params: any) {
+  return request.get(linkUrl + '/list', { params });
+}
+
+// 新增推荐关联
+export function addRecommendLink(data: any) {
+  return request.post(linkUrl, data);
+}
+
+// 删除推荐关联
+export function delRecommendLink(id: number | string) {
+  return request.delete(`${linkUrl}/${id}`);
+}

+ 109 - 12
src/views/platform/decoration/flashSale/index.vue

@@ -119,6 +119,40 @@
         <el-button @click="sortDialog.visible = false">取 消</el-button>
       </template>
     </el-dialog>
+
+    <!-- 选择商品对话框 -->
+    <el-dialog v-model="selectDialog.visible" title="选择商品" width="800px" append-to-body>
+      <div class="search-bar mb-[10px]">
+        <el-input v-model="selectDialog.keyword" placeholder="请输入品牌编号或名称" clearable style="width: 280px" />
+        <el-button type="primary" @click="loadSearchBrands">搜索</el-button>
+      </div>
+      <el-table :data="selectDialog.list" border max-height="400">
+        <el-table-column label="品牌编号" align="center" prop="brandNo" width="120" />
+        <el-table-column label="品牌图片" align="center" width="100">
+          <template #default="scope">
+            <el-image :src="scope.row.coverImage" fit="cover" style="width: 60px; height: 60px" lazy>
+              <template #error><span class="text-gray-400">加载失败</span></template>
+            </el-image>
+          </template>
+        </el-table-column>
+        <el-table-column label="品牌名称" align="center" prop="brandName" />
+        <el-table-column label="操作" align="center" width="80">
+          <template #default="scope">
+            <el-button type="primary" link @click="handleConfirmBrand(scope.row)">确认</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        v-show="selectDialog.total > 0"
+        v-model:page="selectDialog.pageNum"
+        v-model:limit="selectDialog.pageSize"
+        :total="selectDialog.total"
+        @pagination="loadSearchBrands"
+      />
+      <template #footer>
+        <el-button @click="selectDialog.visible = false">取 消</el-button>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
@@ -129,6 +163,7 @@ import { Picture, CircleClose } from '@element-plus/icons-vue';
 import { getDecorationSectionByType, addDecorationSection, updateDecorationSection } from '@/api/decoration/section';
 import { listAdContent, addAdContent, updateAdContent } from '@/api/ad/content';
 import { listByIds } from '@/api/system/oss';
+import { listBrand } from '@/api/product/brand';
 
 const searchKeyword = ref('');
 const defaultBannerUrl = 'https://via.placeholder.com/200x300/1a237e/FFFFFF?text=品牌广告';
@@ -206,21 +241,83 @@ const saveHeaderConfig = async () => {
   } catch (error) { ElMessage.error('保存失败'); }
 };
 
-// 品牌列表(静态数据,等商品接口开发完成后再改)
-const brandList = ref([
-  { id: 1, title: '联想', description: '联想', logoUrl: '/img/联想.jpg' },
-  { id: 2, title: '惠普', description: '惠普', logoUrl: '/img/惠普.jpg' },
-  { id: 3, title: '奔图', description: '奔图', logoUrl: '/img/奔图.jpg' },
-  { id: 4, title: 'MAXHUB', description: 'MAXHUB', logoUrl: '/img/MAXHUB.jpg' },
-  { id: 5, title: '飞利浦', description: '飞利浦', logoUrl: '/img/PHILIPS.jpg' },
-  { id: 6, title: '美的', description: '美的', logoUrl: '/img/Midea.jpg' },
-  { id: 7, title: '格力', description: '格力', logoUrl: '/img/格力.jpg' }
-]);
+// 品牌列表
+const brandList = ref<any[]>([]);
+
+// 加载品牌列表
+const loadBrandList = async () => {
+  try {
+    const res: any = await listBrand({ pageNum: 1, pageSize: 10, isShow: 1 });
+    brandList.value = (res.rows || []).map((item: any) => ({
+      id: item.id,
+      title: item.brandName,
+      description: item.brandDescribe || item.brandName,
+      logoUrl: item.brandBigImageUrl || item.brandLogo
+    }));
+  } catch (error) {
+    console.error('加载品牌列表失败', error);
+    brandList.value = [];
+  }
+};
 
 const handleViewAll = () => { if (bannerConfig.value.link) window.open(bannerConfig.value.link, '_blank'); else ElMessage.info('暂未配置跳转链接'); };
-const handleSearch = () => { ElMessage.info(`搜索: ${searchKeyword.value || '全部'}`); };
 const handleLinkClick = () => { if (headerConfig.value.linkUrl) window.open(headerConfig.value.linkUrl, '_blank'); };
 
+// 选择商品对话框
+const selectDialog = reactive({
+  visible: false,
+  keyword: '',
+  list: [] as any[],
+  total: 0,
+  pageNum: 1,
+  pageSize: 10
+});
+
+// 搜索品牌
+const loadSearchBrands = async () => {
+  try {
+    const res: any = await listBrand({
+      pageNum: selectDialog.pageNum,
+      pageSize: selectDialog.pageSize,
+      brandName: selectDialog.keyword || undefined
+    });
+    selectDialog.list = (res.rows || []).map((item: any) => ({
+      id: item.id,
+      brandNo: item.brandNo,
+      brandName: item.brandName,
+      coverImage: item.brandBigImageUrl || item.brandLogo
+    }));
+    selectDialog.total = res.total || 0;
+  } catch (error) {
+    console.error('搜索品牌失败', error);
+    selectDialog.list = [];
+  }
+};
+
+// 打开搜索弹框
+const handleSearch = () => {
+  selectDialog.keyword = searchKeyword.value;
+  selectDialog.pageNum = 1;
+  selectDialog.visible = true;
+  loadSearchBrands();
+};
+
+// 确认选择品牌
+const handleConfirmBrand = (row: any) => {
+  // 检查是否已存在
+  if (brandList.value.find((b) => String(b.id) === String(row.id))) {
+    ElMessage.warning('该品牌已添加');
+    return;
+  }
+  brandList.value.push({
+    id: row.id,
+    title: row.brandName,
+    description: row.brandName,
+    logoUrl: row.coverImage
+  });
+  ElMessage.success('添加成功');
+};
+
 // 品牌操作
 const handleRemoveBrand = (index: number) => { brandList.value.splice(index, 1); ElMessage.success('已移除'); };
 
@@ -237,7 +334,7 @@ const saveSortConfig = () => {
   ElMessage.success('排序已保存');
 };
 
-onMounted(() => { loadHeaderConfig(); loadBannerConfig(); });
+onMounted(() => { loadHeaderConfig(); loadBannerConfig(); loadBrandList(); });
 </script>
 
 

+ 168 - 164
src/views/platform/industrial/booth/index.vue

@@ -192,11 +192,11 @@
 
       <!-- 分页 -->
       <pagination
-        v-show="filteredProducts.length > 0"
+        v-show="newProductPagination.total > 0"
         v-model:page="newProductPagination.pageNum"
         v-model:limit="newProductPagination.pageSize"
-        :total="filteredProducts.length"
-        @pagination="() => {}"
+        :total="newProductPagination.total"
+        @pagination="loadAvailableProducts"
       />
 
       <template #footer>
@@ -240,7 +240,14 @@
 <script setup name="IndustrialBooth" lang="ts">
 import { ref, reactive, computed, watch, nextTick, onMounted, onUnmounted } from 'vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
-import { Close, Picture, ArrowLeft, ArrowRight, View, Plus, Upload } from '@element-plus/icons-vue';
+import { Close, Picture, ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
+import { listProduct } from '@/api/product/base';
+import { listRecommend, listRecommendLink, addRecommendLink, delRecommendLink } from '@/api/product/recommend';
+
+// 推荐位编号(工业装修-轮播展位商品)
+const recommendNo = 'industrial_booth';
+const recommendId = ref<number | null>(null);
+const loading = ref(false);
 
 // 对话框
 const dialog = reactive({
@@ -263,70 +270,14 @@ const importProductIds = ref('');
 // 搜索关键词
 const searchKeyword = ref('');
 
-// 可选商品列表(模拟数据)
-const availableProducts = ref([
-  {
-    id: '002169823',
-    name: '江润双色塑钢培训椅',
-    imageUrl: '/img/江润双色塑钢培训椅.png',
-    price: '299.00'
-  },
-  {
-    id: '002169822',
-    name: '江润多媒体讲台',
-    imageUrl: '/img/江润多媒体讲台.png',
-    price: '799.00'
-  },
-  {
-    id: '002169821',
-    name: '江润六边形折叠培训桌 800*500*750mm (直径 1.6m)',
-    imageUrl: '/img/江润六边形折叠培训桌.png',
-    price: '699.00'
-  },
-  {
-    id: '002169820',
-    name: '梦洁200*230cm锦玉梦韵四件套',
-    imageUrl: '/img/梦洁锦玉梦韵四件套.png',
-    price: '1299.00'
-  },
-  {
-    id: '002169819',
-    name: '洁丽雅纯棉四件套2*2.3M',
-    imageUrl: '/img/洁丽雅纯棉四件套.png',
-    price: '249.00'
-  },
-  {
-    id: '002169818',
-    name: '江润实验台2000*750*800mm',
-    imageUrl: '/img/江润实验台.png',
-    price: '3699.00'
-  },
-  {
-    id: '002169817',
-    name: '江润办公屏风办公桌',
-    imageUrl: '/img/江润办公屏风办公桌.png',
-    price: '1599.00'
-  },
-  {
-    id: '002169816',
-    name: '创维100V5-HG1会议平板触控一体机',
-    imageUrl: '/img/创维100V5-HG1会议平板触控一体机.png',
-    price: '12999.00'
-  }
-]);
+// 可选商品列表(从接口获取)
+const availableProducts = ref<any[]>([]);
 
 // 选中的商品ID列表(用于新增商品标签页)
 const selectedProductIds = ref<string[]>([]);
 
 // 新增商品分页
 const newProductPagination = reactive({
-  pageNum: 1,
-  pageSize: 20,
-  total: 1895427
-});
-
-// 已选商品分页
-const selectedProductPagination = reactive({
   pageNum: 1,
   pageSize: 20,
   total: 0
@@ -340,58 +291,89 @@ const pageSize = 5; // 每页显示5个商品
 let autoPlayTimer: ReturnType<typeof setInterval> | null = null;
 const autoPlayInterval = 3000; // 3秒切换一次
 
-// 模拟数据 - 已选商品列表
-const selectedProducts = ref([
-  {
-    id: '000294732',
-    name: '江润双色塑钢培训椅',
-    imageUrl: '/img/江润双色塑钢培训椅.png',
-    price: '299.00',
-    sort: 9
-  },
-  {
-    id: '000130005',
-    name: '江润六边形折叠培训桌 800*500*750mm',
-    imageUrl: '/img/江润六边形折叠培训桌.png',
-    price: '699.00',
-    sort: 8
-  },
-  {
-    id: '000371498',
-    name: '梦洁200*230cm锦玉梦韵四件套',
-    imageUrl: '/img/梦洁锦玉梦韵四件套.png',
-    price: '1299.00',
-    sort: 7
-  },
-  {
-    id: '000207453',
-    name: '洁丽雅纯棉四件套2*2.3M',
-    imageUrl: '/img/洁丽雅纯棉四件套.png',
-    price: '249.00',
-    sort: 6
-  },
-  {
-    id: '000359317',
-    name: '江润实验台2000*750*800mm',
-    imageUrl: '/img/江润实验台.png',
-    price: '3699.00',
-    sort: 5
-  },
-  {
-    id: '000123456',
-    name: '江润办公屏风办公桌',
-    imageUrl: '/img/江润办公屏风办公桌.png',
-    price: '1599.00',
-    sort: 4
-  },
-  {
-    id: '000789012',
-    name: '创维100V5-HG1会议平板触控一体机',
-    imageUrl: '/img/创维100V5-HG1会议平板触控一体机.png',
-    price: '12999.00',
-    sort: 3
+// 已选商品列表(从接口获取)
+const selectedProducts = ref<any[]>([]);
+
+// 获取可选商品列表
+const loadAvailableProducts = async () => {
+  try {
+    const params: any = {
+      pageNum: newProductPagination.pageNum,
+      pageSize: newProductPagination.pageSize
+    };
+    if (searchKeyword.value) {
+      params.itemName = searchKeyword.value;
+    }
+    const res: any = await listProduct(params);
+    // 字段映射
+    availableProducts.value = (res.rows || []).map((item: any) => ({
+      id: item.id,
+      productNo: item.productNo,
+      name: item.itemName,
+      imageUrl: item.productImageUrl || item.productImage,
+      price: item.minSellingPrice || item.memberPrice || '0.00'
+    }));
+    newProductPagination.total = res.total || 0;
+  } catch (error) {
+    console.error('获取商品列表失败', error);
+    availableProducts.value = [];
+  }
+};
+
+// 获取推荐位ID
+const loadRecommendId = async () => {
+  try {
+    const res: any = await listRecommend({ recommendNo, pageSize: 1 });
+    if (res.rows && res.rows.length > 0) {
+      recommendId.value = res.rows[0].id;
+    }
+  } catch (error) {
+    console.error('获取推荐位失败', error);
+  }
+};
+
+// 获取已选商品列表(通过推荐关联)
+const loadSelectedProducts = async () => {
+  loading.value = true;
+  try {
+    if (!recommendId.value) {
+      await loadRecommendId();
+    }
+    if (!recommendId.value) {
+      selectedProducts.value = [];
+      return;
+    }
+    // 先获取推荐关联的商品ID列表
+    const linkRes: any = await listRecommendLink({ recommendId: recommendId.value, pageSize: 100 });
+    const links = linkRes.rows || [];
+    if (links.length === 0) {
+      selectedProducts.value = [];
+      return;
+    }
+    // 获取商品详情
+    const productIds = links.map((link: any) => link.productId);
+    const productRes: any = await listProduct({ ids: productIds.join(','), pageSize: 100 });
+    const productMap = new Map((productRes.rows || []).map((p: any) => [p.id, p]));
+    // 组装数据
+    selectedProducts.value = links.map((link: any, index: number) => {
+      const product: any = productMap.get(link.productId) || {};
+      return {
+        id: product.id || link.productId,
+        linkId: link.id, // 关联ID,用于删除
+        productNo: product.productNo,
+        name: product.itemName || `商品${link.productId}`,
+        imageUrl: product.productImageUrl || product.productImage,
+        price: product.minSellingPrice || product.memberPrice || '0.00',
+        sort: links.length - index // 默认排序
+      };
+    });
+  } catch (error) {
+    console.error('获取已选商品失败', error);
+    selectedProducts.value = [];
+  } finally {
+    loading.value = false;
   }
-]);
+};
 
 // 计算当前显示的商品(按排序值降序排列)
 const sortedProducts = computed(() => {
@@ -421,8 +403,10 @@ const hasNext = computed(() => {
 });
 
 // 查看推荐商品
-const handleViewProducts = () => {
+const handleViewProducts = async () => {
   dialog.visible = true;
+  // 每次打开都重新加载数据
+  await loadSelectedProducts();
 };
 
 // 对话框关闭
@@ -436,6 +420,8 @@ const handleAddProduct = () => {
   selectedProductIds.value = [];
   searchKeyword.value = '';
   newProductPagination.pageNum = 1;
+  // 加载可选商品列表
+  loadAvailableProducts();
   // 等待DOM更新后,清除表格选中状态
   nextTick(() => {
     if (newProductTableRef.value) {
@@ -458,8 +444,7 @@ const handleSelectDialogClose = () => {
 // 搜索商品
 const handleSearchProducts = () => {
   newProductPagination.pageNum = 1;
-  // 这里可以调用搜索接口
-  ElMessage.success('搜索功能开发中...');
+  loadAvailableProducts();
 };
 
 // 表格选择变化
@@ -470,58 +455,59 @@ const handleSelectionChange = (selection: any[]) => {
 
 
 // 确认选择商品
-const handleConfirmSelect = () => {
+const handleConfirmSelect = async () => {
   if (selectedProductIds.value.length === 0) {
     ElMessage.warning('请至少选择一个商品');
     return;
   }
 
-  // 添加选中的商品到已选列表
-  selectedProductIds.value.forEach((id) => {
-    const product = availableProducts.value.find((p) => p.id === id);
-    if (product && !selectedProducts.value.find((p) => p.id === id)) {
-      selectedProducts.value.push({
-        ...product,
-        sort: Math.max(...selectedProducts.value.map((p) => p.sort), 0) + 1
-      });
+  try {
+    if (!recommendId.value) {
+      await loadRecommendId();
     }
-  });
-
-  ElMessage.success(`成功添加 ${selectedProductIds.value.length} 个商品`);
-  handleSelectDialogClose();
-};
-
-// 过滤后的可选商品列表(不分页,用于搜索)
-const filteredProducts = computed(() => {
-  let products = [...availableProducts.value];
-  
-  // 根据搜索关键词过滤
-  if (searchKeyword.value) {
-    const keyword = searchKeyword.value.toLowerCase();
-    products = products.filter(
-      (p) =>
-        p.id.toLowerCase().includes(keyword) ||
-        p.name.toLowerCase().includes(keyword)
-    );
+    if (!recommendId.value) {
+      ElMessage.error('推荐位不存在,请先创建');
+      return;
+    }
+    // 批量添加推荐关联,统计实际添加数量
+    let addedCount = 0;
+    let skippedCount = 0;
+    for (const productId of selectedProductIds.value) {
+      // 检查是否已存在
+      if (selectedProducts.value.find((p) => String(p.id) === String(productId))) {
+        skippedCount++;
+      } else {
+        await addRecommendLink({ recommendId: recommendId.value, productId });
+        addedCount++;
+      }
+    }
+    if (addedCount > 0) {
+      ElMessage.success(`成功添加 ${addedCount} 个商品${skippedCount > 0 ? `,${skippedCount} 个已存在被跳过` : ''}`);
+    } else {
+      ElMessage.warning('所选商品均已存在');
+    }
+    handleSelectDialogClose();
+    // 刷新已选列表
+    await loadSelectedProducts();
+  } catch (error) {
+    ElMessage.error('添加失败');
   }
+};
 
-  return products;
-});
-
-// 分页后的可选商品列表
+// 分页后的可选商品列表(过滤掉已选的商品)
 const filteredAvailableProducts = computed(() => {
-  const start = (newProductPagination.pageNum - 1) * newProductPagination.pageSize;
-  const end = start + newProductPagination.pageSize;
-  return filteredProducts.value.slice(start, end);
+  const selectedIds = selectedProducts.value.map((p) => String(p.id));
+  return availableProducts.value.filter((item) => !selectedIds.includes(String(item.id)));
 });
 
-// 更新分页总数
+// 分页变化
 watch(
-  () => filteredProducts.value.length,
-  (newTotal) => {
-    newProductPagination.total = newTotal;
-  },
-  { immediate: true }
+  () => [newProductPagination.pageNum, newProductPagination.pageSize],
+  () => {
+    if (selectDialog.visible) {
+      loadAvailableProducts();
+    }
+  }
 );
 
 
@@ -582,20 +568,28 @@ const handleConfirmImport = () => {
 
 // 删除商品
 const handleDeleteProduct = (id: string) => {
+  const product = selectedProducts.value.find((item) => String(item.id) === String(id));
   ElMessageBox.confirm('是否确认删除该商品?', '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
   })
-    .then(() => {
-      const index = selectedProducts.value.findIndex((item) => item.id === id);
-      if (index !== -1) {
-        selectedProducts.value.splice(index, 1);
+    .then(async () => {
+      try {
+        if (product?.linkId) {
+          await delRecommendLink(product.linkId);
+        }
+        const index = selectedProducts.value.findIndex((item) => String(item.id) === String(id));
+        if (index !== -1) {
+          selectedProducts.value.splice(index, 1);
+        }
         ElMessage.success('删除成功');
         // 调整页码确保不越界
         if (currentPage.value >= totalPages.value && currentPage.value > 0) {
           currentPage.value = totalPages.value - 1;
         }
+      } catch (error) {
+        ElMessage.error('删除失败');
       }
     })
     .catch(() => {});
@@ -629,20 +623,28 @@ const handleNext = () => {
 
 // 移除商品(从展示区域移除)
 const handleRemoveProduct = (id: string) => {
+  const product = selectedProducts.value.find((item) => String(item.id) === String(id));
   ElMessageBox.confirm('是否确认从展示区域移除该商品?', '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
   })
-    .then(() => {
-      const index = selectedProducts.value.findIndex((item) => item.id === id);
-      if (index !== -1) {
-        selectedProducts.value.splice(index, 1);
+    .then(async () => {
+      try {
+        if (product?.linkId) {
+          await delRecommendLink(product.linkId);
+        }
+        const index = selectedProducts.value.findIndex((item) => String(item.id) === String(id));
+        if (index !== -1) {
+          selectedProducts.value.splice(index, 1);
+        }
         ElMessage.success('移除成功');
         // 调整页码确保不越界
         if (currentPage.value >= totalPages.value && currentPage.value > 0) {
           currentPage.value = totalPages.value - 1;
         }
+      } catch (error) {
+        ElMessage.error('移除失败');
       }
     })
     .catch(() => {});
@@ -676,6 +678,8 @@ const stopAutoPlay = () => {
 };
 
 onMounted(() => {
+  // 加载已选商品
+  loadSelectedProducts();
   // 启动自动轮播
   startAutoPlay();
 });