Prechádzať zdrojové kódy

企业购管理页面修改

hurx 1 týždeň pred
rodič
commit
a693d96bcd

+ 12 - 0
src/api/enterprisePurchase/carousel/index.ts

@@ -61,3 +61,15 @@ export const delCarousel = (id: string | number | Array<string | number>) => {
     method: 'delete'
   });
 };
+
+export function changeStatus(id: string | number, status: number) {
+  const data = {
+    id,
+    status
+  };
+  return request({
+    url: '/mall/carousel/changeStatus',
+    method: 'put',
+    data: data
+  });
+}

+ 12 - 0
src/api/enterprisePurchase/categoryMain/index.ts

@@ -61,3 +61,15 @@ export const delCategoryMain = (id: string | number | Array<string | number>) =>
     method: 'delete'
   });
 };
+
+export function changeStatus(id: string | number, status: number) {
+  const data = {
+    id,
+    status
+  };
+  return request({
+    url: '/mall/categoryMain/changeStatus',
+    method: 'put',
+    data: data
+  });
+}

+ 12 - 0
src/api/enterprisePurchase/headerCategory/index.ts

@@ -61,3 +61,15 @@ export const delHeaderCategory = (id: string | number | Array<string | number>)
     method: 'delete'
   });
 };
+
+export function changeStatus(id: string | number, status: number) {
+  const data = {
+    id,
+    status
+  };
+  return request({
+    url: '/mall/headerCategory/changeStatus',
+    method: 'put',
+    data: data
+  });
+}

+ 12 - 0
src/api/enterprisePurchase/quickEntryItems/index.ts

@@ -61,3 +61,15 @@ export const delQuickEntryItems = (id: string | number | Array<string | number>)
     method: 'delete'
   });
 };
+
+export function changeStatus(id: string | number, status: number) {
+  const data = {
+    id,
+    status
+  };
+  return request({
+    url: '/mall/quickEntryItems/changeStatus',
+    method: 'put',
+    data: data
+  });
+}

+ 12 - 0
src/api/enterprisePurchase/recommendCategoryConfig/index.ts

@@ -65,3 +65,15 @@ export const delRecommendCategoryConfig = (id: string | number | Array<string |
     method: 'delete'
   });
 };
+
+export function changeStatus(id: string | number, status: number) {
+  const data = {
+    id,
+    status
+  };
+  return request({
+    url: '/mall/recommendCategoryConfig/changeStatus',
+    method: 'put',
+    data: data
+  });
+}

+ 2 - 0
src/api/enterprisePurchase/recommendCategoryConfig/types.ts

@@ -39,6 +39,8 @@ export interface RecommendCategoryConfigVO {
    */
   selectedProductIds: string | number;
 
+  selectedProducts: any[];
+
   /**
    * 排序
    */

+ 177 - 83
src/views/enterprisePurchase/index.vue

@@ -202,7 +202,13 @@
               </el-table-column>
               <el-table-column label="状态" width="100" align="center">
                 <template #default="scope">
-                  <el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0" active-color="#13ce66" />
+                  <el-switch
+                    v-model="scope.row.status"
+                    :active-value="1"
+                    :inactive-value="0"
+                    @change="handleCarouselStatusChange(scope.row)"
+                    active-color="#13ce66"
+                  />
                 </template>
               </el-table-column>
               <el-table-column label="操作" width="150" align="center">
@@ -308,7 +314,7 @@
             <el-table-column prop="link" label="跳转地址" show-overflow-tooltip />
             <el-table-column label="状态" width="100" align="center">
               <template #default="{ row }">
-                <el-switch v-model="row.status" :active-value="1" :inactive-value="0" />
+                <el-switch v-model="row.status" :active-value="1" :inactive-value="0" @change="handleQuickEntryStatusChange(row)" />
               </template>
             </el-table-column>
             <el-table-column label="操作" width="150" fixed="right" align="center">
@@ -423,7 +429,13 @@
             </el-table-column>
             <el-table-column label="状态" width="100" align="center">
               <template #default="scope">
-                <el-switch v-model="scope.row.status" :active-value="1" :inactive-value="0" active-color="#13ce66" />
+                <el-switch
+                  v-model="scope.row.status"
+                  :active-value="1"
+                  :inactive-value="0"
+                  @change="handleCategoryStatusChange(scope.row)"
+                  active-color="#13ce66"
+                />
               </template>
             </el-table-column>
             <el-table-column label="操作" width="150" align="center" fixed="right">
@@ -510,7 +522,13 @@
             </el-table-column>
             <el-table-column label="状态" width="100" align="center">
               <template #default="{ row }">
-                <el-switch v-model="row.status" :active-value="1" :inactive-value="0" active-color="#13ce66" />
+                <el-switch
+                  v-model="row.status"
+                  :active-value="1"
+                  :inactive-value="0"
+                  @change="handleHeaderCategoryStatusChange(row)"
+                  active-color="#13ce66"
+                />
               </template>
             </el-table-column>
             <el-table-column label="操作" width="150" fixed="right" align="center">
@@ -846,7 +864,13 @@
             </el-table-column>
             <el-table-column label="启用状态" width="100" align="center">
               <template #default="{ row }">
-                <el-switch v-model="row.status" :active-value="1" :inactive-value="0" active-color="#13ce66" />
+                <el-switch
+                  v-model="row.status"
+                  :active-value="1"
+                  :inactive-value="0"
+                  @change="handleRecommendStatusChange(row)"
+                  active-color="#13ce66"
+                />
               </template>
             </el-table-column>
             <el-table-column label="操作" width="220" align="center" fixed="right">
@@ -1371,8 +1395,8 @@
         <el-form-item v-if="recommendForm.type === 'category'" label="映射分类:">
           <el-cascader
             v-model="recommendForm.categoryValue"
-            :options="mockCategoryOptions"
-            :props="{ checkStrictly: true, expandTrigger: 'hover' }"
+            :options="categoryOptions"
+            :props="{ value: 'id', label: 'label', children: 'children', checkStrictly: true, expandTrigger: 'hover' }"
             placeholder="请选择一级/二级/三级分类"
             style="width: 100%"
             filterable
@@ -1434,6 +1458,7 @@
 
 <script lang="ts" setup>
 import UploadImage from '@/components/upload-image/index.vue';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 import { ref, reactive, computed, watch, onMounted, onUnmounted, nextTick } from 'vue';
 import { ElMessage, ElMessageBox } from 'element-plus';
 import {
@@ -1447,9 +1472,16 @@ import {
 import { SearchConfigVO, SearchConfigQuery, SearchConfigForm } from '@/api/enterprisePurchase/searchConfig/types';
 import { listAdLeft, getAdLeft, delAdLeft, addAdLeft, updateAdLeft, getCurrentAdLeft } from '@/api/enterprisePurchase/adLeft';
 import { AdLeftVO, AdLeftQuery, AdLeftForm } from '@/api/enterprisePurchase/adLeft/types';
-import { listCarousel, getCarousel, delCarousel, addCarousel, updateCarousel } from '@/api/enterprisePurchase/carousel';
+import { listCarousel, getCarousel, delCarousel, addCarousel, updateCarousel, changeStatus } from '@/api/enterprisePurchase/carousel';
 import { CarouselVO, CarouselQuery, CarouselForm } from '@/api/enterprisePurchase/carousel/types';
-import { listCategoryMain, getCategoryMain, delCategoryMain, addCategoryMain, updateCategoryMain } from '@/api/enterprisePurchase/categoryMain';
+import {
+  listCategoryMain,
+  getCategoryMain,
+  delCategoryMain,
+  addCategoryMain,
+  updateCategoryMain,
+  changeStatus as categoryMainChangeStatus
+} from '@/api/enterprisePurchase/categoryMain';
 import { CategoryMainVO, CategoryMainQuery, CategoryMainForm } from '@/api/enterprisePurchase/categoryMain/types';
 import { listScenarioCards, getScenarioCards, delScenarioCards, addScenarioCards, updateScenarioCards } from '@/api/enterprisePurchase/scenarioCards';
 import { ScenarioCardsVO, ScenarioCardsQuery, ScenarioCardsForm } from '@/api/enterprisePurchase/scenarioCards/types';
@@ -1462,25 +1494,23 @@ import {
   getQuickEntryItems,
   delQuickEntryItems,
   addQuickEntryItems,
-  updateQuickEntryItems
+  updateQuickEntryItems,
+  changeStatus as quickEntryItemsUpdateStatus
 } from '@/api/enterprisePurchase/quickEntryItems';
 import { QuickEntryItemsVO, QuickEntryItemsQuery, QuickEntryItemsForm } from '@/api/enterprisePurchase/quickEntryItems/types';
 import { listBase } from '@/api/pmsProduct/base';
 import { listBrand } from '@/api/product/brand';
-import {
-  listAdModuleConfig,
-  getAdModuleConfig,
-  delAdModuleConfig,
-  addAdModuleConfig,
-  updateAdModuleConfig
-} from '@/api/enterprisePurchase/adModuleConfig';
+import { categoryTree } from '@/api/product/base/index';
+import { categoryTreeVO } from '@/api/product/category/types';
+import { listAdModuleConfig, getAdModuleConfig, addAdModuleConfig, updateAdModuleConfig } from '@/api/enterprisePurchase/adModuleConfig';
 import { AdModuleConfigVO, AdModuleConfigQuery, AdModuleConfigForm } from '@/api/enterprisePurchase/adModuleConfig/types';
 import {
   listHeaderCategory,
   getHeaderCategory,
   delHeaderCategory,
   addHeaderCategory,
-  updateHeaderCategory
+  updateHeaderCategory,
+  changeStatus as headerCategoryChangeStatus
 } from '@/api/enterprisePurchase/headerCategory';
 import {
   listRecommendThemeConfig,
@@ -1495,7 +1525,8 @@ import {
   getRecommendCategoryConfig,
   delRecommendCategoryConfig,
   addRecommendCategoryConfig,
-  updateRecommendCategoryConfig
+  updateRecommendCategoryConfig,
+  changeStatus as recommendThemeChangeStatus
 } from '@/api/enterprisePurchase/recommendCategoryConfig';
 import {
   RecommendCategoryConfigVO,
@@ -1558,6 +1589,63 @@ const leftAdForm = reactive({
   leftAdImage: '',
   leftAdLink: ''
 });
+// 轮播图状态切换
+const handleCarouselStatusChange = async (row: any) => {
+  const oldValue = row.status; // 保存旧值(0 或 1)
+  try {
+    await changeStatus(row.id, row.status); // 传新值
+    proxy?.$modal.msgSuccess('操作成功');
+  } catch {
+    row.status = oldValue; // 失败回滚
+    proxy?.$modal.msgError('操作失败,请重试');
+  }
+};
+
+// 轮播图状态切换
+const handleCategoryStatusChange = async (row: any) => {
+  const oldValue = row.status; // 保存旧值(0 或 1)
+  try {
+    await categoryMainChangeStatus(row.id, row.status); // 传新值
+    proxy?.$modal.msgSuccess('操作成功');
+  } catch {
+    row.status = oldValue; // 失败回滚
+    proxy?.$modal.msgError('操作失败,请重试');
+  }
+};
+// 头部分类状态切换
+const handleHeaderCategoryStatusChange = async (row: any) => {
+  const oldValue = row.status; // 保存旧值(0 或 1)
+  try {
+    await headerCategoryChangeStatus(row.id, row.status); // 传新值
+    proxy?.$modal.msgSuccess('操作成功');
+  } catch {
+    row.status = oldValue; // 失败回滚
+    proxy?.$modal.msgError('操作失败,请重试');
+  }
+};
+// 快捷入口状态切换
+const handleQuickEntryStatusChange = async (row: any) => {
+  const oldValue = row.status; // 保存旧值(0 或 1)
+  try {
+    await quickEntryItemsUpdateStatus(row.id, row.status); // 传新值
+    proxy?.$modal.msgSuccess('操作成功');
+  } catch {
+    row.status = oldValue; // 失败回滚
+    proxy?.$modal.msgError('操作失败,请重试');
+  }
+};
+
+// 推荐状态切换
+const handleRecommendStatusChange = async (row: any) => {
+  const oldValue = row.status; // 保存旧值(0 或 1)
+  try {
+    await recommendThemeChangeStatus(row.id, row.status); // 传新值
+    proxy?.$modal.msgSuccess('操作成功');
+  } catch {
+    row.status = oldValue; // 失败回滚
+    proxy?.$modal.msgError('操作失败,请重试');
+  }
+};
 
 // 左侧广告配置ID(单例)
 const leftAdId = ref<string | number>('');
@@ -1827,7 +1915,7 @@ const moveRow = async (index: number, direction: number) => {
       const row = carouselList.value[i];
       await updateCarousel({
         id: row.id,
-        imageUrl: row.image || row.imageUrl,
+        imageUrl: row.imageUrl,
         link: row.link,
         target: row.target,
         status: row.status,
@@ -1843,9 +1931,9 @@ const moveRow = async (index: number, direction: number) => {
 // 颜色转换工具:Hex 转 RGBA
 const hexToRgba = (hex, opacity) => {
   if (!hex) return `rgba(255, 255, 255, ${opacity})`;
-  let r = parseInt(hex.slice(1, 3), 16);
-  let g = parseInt(hex.slice(3, 5), 16);
-  let b = parseInt(hex.slice(5, 7), 16);
+  const r = parseInt(hex.slice(1, 3), 16);
+  const g = parseInt(hex.slice(3, 5), 16);
+  const b = parseInt(hex.slice(5, 7), 16);
   return `rgba(${r}, ${g}, ${b}, ${opacity})`;
 };
 
@@ -1960,7 +2048,9 @@ const handleDeleteLeftAd = () => {
 
 // 分类设置模块逻辑
 const categoryThemeColor = ref('#e60012');
-const syncCategoryOptions = ['办公电脑', '办公设备', '办公家电', '文具耗材', '日用百货', '工业品', '食品饮料', '车载用品', '运动户外'];
+const syncCategoryOptions = computed(() => {
+  return (categoryOptions.value || []).map((item: any) => item.label);
+});
 
 const categoryList = ref<CategoryMainVO[]>([]);
 
@@ -2502,7 +2592,7 @@ const adModules = ref([
       { id: 502, productName: '得力笔记本', imageUrl: '/static/images/purchase/notebook_deli.jpg', price: '34.9' }
     ]
   }
-]);
+]) as any;
 
 const adDialogVisible = ref(false);
 const currentAdIdx = ref(-1);
@@ -2510,29 +2600,38 @@ const currentItemIdx = ref(-1);
 const adForm = reactive({ title: '', titleColor: '#333333', subTitle: '', subTitleColor: '#f58220', items: [] });
 
 // 实时预览辅助函数
-const getAdTitleStyle = (index, type) => {
+const getAdTitleStyle = (index: number, type: string) => {
   const isEditing = adDialogVisible.value && currentAdIdx.value === index;
   const key = type === 'main' ? 'titleColor' : 'subTitleColor';
   const defaultColor = type === 'main' ? '#333' : '#999';
-  const color = isEditing ? adForm[key] : adModules.value[index][key] || defaultColor;
+  const color = isEditing ? adForm[key] : adModules.value[index]?.[key] || defaultColor;
   return { color };
 };
 
-const getAdTitleText = (index, type) => {
+const getAdTitleText = (index: number, type: string) => {
   const isEditing = adDialogVisible.value && currentAdIdx.value === index;
   const key = type === 'main' ? 'title' : 'subTitle';
-  return isEditing ? adForm[key] : adModules.value[index][key];
+  return isEditing ? adForm[key] : adModules.value[index]?.[key] || '';
 };
 
-const handleEditAd = (index) => {
+const emptyItem = () => ({ id: null, productId: '', productName: '', imageUrl: '', price: '', tagText: '', tagLink: '', salesCount: '' });
+const slotCounts = [4, 2, 2, 2, 2]; // 每个模块固定条目数
+
+const handleEditAd = (index: number) => {
   currentAdIdx.value = index;
-  const ad = adModules.value[index];
-  Object.assign(adForm, JSON.parse(JSON.stringify(ad)));
+  const ad = adModules.value[index] || {};
+  const data = JSON.parse(JSON.stringify(ad));
+  // 确保 items 有固定数量的条目(不够用空模板补齐)
+  const count = slotCounts[index] || 2;
+  while (data.items.length < count) {
+    data.items.push(emptyItem());
+  }
+  Object.assign(adForm, data);
   adDialogVisible.value = true;
 };
 
 const submitAdForm = async () => {
-  const moduleData = adModules.value[currentAdIdx.value];
+  const moduleData = adModules.value[currentAdIdx.value] as any;
   if (!moduleData) return;
 
   const data: AdModuleConfigForm = {
@@ -2545,15 +2644,17 @@ const submitAdForm = async () => {
     jumpLink: '',
     status: 1,
     sortOrder: currentAdIdx.value,
-    adModuleItemList: adForm.items.map((item: any) => ({
-      productId: item.productId || item.id,
-      productName: item.productName || '',
-      imageUrl: item.imageUrl || '',
-      price: item.price || 0,
-      tagText: item.tagText || '',
-      tagLink: item.tagLink || '',
-      salesCount: item.salesCount || 0
-    }))
+    adModuleItemList: adForm.items
+      .filter((item: any) => item.productId || item.imageUrl)
+      .map((item: any) => ({
+        productId: item.productId || item.id,
+        productName: item.productName || '',
+        imageUrl: item.imageUrl || '',
+        price: item.price || 0,
+        tagText: item.tagText || '',
+        tagLink: item.tagLink || '',
+        salesCount: item.salesCount || 0
+      }))
   };
 
   try {
@@ -2585,10 +2686,11 @@ const submitAdForm = async () => {
 
 // 获取广告模块配置列表
 const getAdModuleList = async () => {
+  const defaults = adModules.value; // 保留当前 mock 数据作为缺省填充
   try {
     const res = await listAdModuleConfig();
     if (res.code === 200 && res.rows && res.rows.length > 0) {
-      adModules.value = res.rows.map((item: AdModuleConfigVO) => ({
+      const apiList = res.rows.map((item: AdModuleConfigVO) => ({
         ...item,
         title: item.mainTitle || '',
         titleColor: item.mainTitleColor || '#333333',
@@ -2606,10 +2708,11 @@ const getAdModuleList = async () => {
           salesCount: sub.salesCount || 0
         }))
       }));
+      // 确保始终有 5 个模块(模板固定访问 adModules[0]~[4])
+      adModules.value = Array.from({ length: 5 }, (_, i) => apiList[i] || defaults[i] || { title: '', items: [] });
     }
   } catch (error) {
     console.error('获取广告模块配置失败:', error);
-    ElMessage.error('获取广告模块配置失败');
   }
 };
 
@@ -2702,36 +2805,27 @@ const recommendForm = reactive({
   status: 1
 });
 
-const mockCategoryOptions = [
-  {
-    value: 'bg',
-    label: '办公设备',
-    children: [
-      {
-        value: 'dn',
-        label: '办公电脑',
-        children: [
-          { value: 'bjb', label: '笔记本' },
-          { value: 'tsj', label: '台式机' }
-        ]
-      }
-    ]
-  },
-  {
-    value: 'wj',
-    label: '文具耗材',
-    children: [
-      {
-        value: 'dy',
-        label: '打印耗材',
-        children: [
-          { value: 'fyz', label: '复印纸' },
-          { value: 'xhg', label: '硒鼓' }
-        ]
-      }
-    ]
+const categoryOptions = ref<categoryTreeVO[]>([]);
+
+const getCategoryTreeData = async () => {
+  try {
+    const res = await categoryTree({ dataSource: 'A10' } as any);
+    categoryOptions.value = (res.data || []) as any[];
+  } catch (error) {
+    console.error('获取分类树失败:', error);
   }
-];
+};
+
+const findNodeById = (nodes: any[], id: string | number): any => {
+  for (const node of nodes) {
+    if (node.id === id) return node;
+    if (node.children) {
+      const found = findNodeById(node.children, id);
+      if (found) return found;
+    }
+  }
+  return null;
+};
 
 const handleAddRecommend = () => {
   recommendEditIndex.value = -1;
@@ -2754,22 +2848,18 @@ const handleEditRecommend = (row, index) => {
   recommendDialogVisible.value = true;
 };
 
-const getLabelsByValues = (values, options) => {
-  const labels = [];
-  let currentOptions = options;
+const getLabelsByValues = (values: (string | number)[], tree: any[]): string => {
+  const labels: string[] = [];
   for (const val of values) {
-    const target = currentOptions.find((opt) => opt.value === val);
-    if (target) {
-      labels.push(target.label);
-      currentOptions = target.children || [];
-    }
+    const node = findNodeById(tree, val);
+    if (node) labels.push(node.label);
   }
   return labels.join(' > ');
 };
 
 const handleRecommendCategoryChange = (val) => {
   if (val && val.length > 0) {
-    recommendForm.categoryLabel = getLabelsByValues(val, mockCategoryOptions);
+    recommendForm.categoryLabel = getLabelsByValues(val, categoryOptions.value);
   } else {
     recommendForm.categoryLabel = '';
   }
@@ -3045,7 +3135,10 @@ const getProductList = async () => {
         id: item.id,
         name: item.itemName || '',
         image: item.productImage || item.productImageUrl || '',
-        price: item.memberPrice ?? item.minSellingPrice ?? item.marketPrice ?? ''
+        price: item.memberPrice ?? item.minSellingPrice ?? item.marketPrice ?? '',
+        productNo: item.productNo || '',
+        isSelf: item.isSelf,
+        minOrderQuantity: item.minOrderQuantity || 1
       }));
       productTotal.value = res.total || 0;
     }
@@ -3304,6 +3397,7 @@ onMounted(() => {
   getAdModuleList();
   getRecommendThemeConfigList();
   getRecommendCategoryList();
+  getCategoryTreeData();
   // 获取左侧广告配置
   nextTick(() => {
     updateNavArrows();