牛奶 1 месяц назад
Родитель
Сommit
a12746f96c
67 измененных файлов с 4821 добавлено и 187 удалено
  1. 10 0
      src/api/home/diy.ts
  2. 9 0
      src/api/home/index.ts
  3. BIN
      src/assets/images/figure.png
  4. BIN
      src/assets/images/pcdiy/brand1.png
  5. BIN
      src/assets/images/pcdiy/code.png
  6. BIN
      src/assets/images/pcdiy/floor1.png
  7. BIN
      src/assets/images/pcdiy/floor2.png
  8. BIN
      src/assets/images/pcdiy/layout2.png
  9. BIN
      src/assets/images/pcdiy/layout4.png
  10. BIN
      src/assets/images/pcdiy/logo1.png
  11. BIN
      src/assets/images/pcdiy/logo2.png
  12. BIN
      src/assets/images/pcdiy/style10-1.png
  13. BIN
      src/assets/images/pcdiy/style10-2.png
  14. BIN
      src/assets/images/pcdiy/style11-1.png
  15. BIN
      src/assets/images/pcdiy/style11-2.png
  16. BIN
      src/assets/images/pcdiy/style11-3.png
  17. BIN
      src/assets/images/pcdiy/style13-1.png
  18. BIN
      src/assets/images/pcdiy/style13-2.png
  19. BIN
      src/assets/images/pcdiy/titlle1.png
  20. BIN
      src/assets/images/pcdiy/titlle10.png
  21. BIN
      src/assets/images/pcdiy/titlle11.png
  22. BIN
      src/assets/images/pcdiy/titlle12.png
  23. BIN
      src/assets/images/pcdiy/titlle13.png
  24. BIN
      src/assets/images/pcdiy/titlle14.png
  25. BIN
      src/assets/images/pcdiy/titlle15.png
  26. BIN
      src/assets/images/pcdiy/titlle2.png
  27. BIN
      src/assets/images/pcdiy/titlle3.png
  28. BIN
      src/assets/images/pcdiy/titlle4.png
  29. BIN
      src/assets/images/pcdiy/titlle5.png
  30. BIN
      src/assets/images/pcdiy/titlle6.png
  31. BIN
      src/assets/images/pcdiy/titlle7.png
  32. BIN
      src/assets/images/pcdiy/titlle8.png
  33. BIN
      src/assets/images/pcdiy/titlle9.png
  34. BIN
      src/assets/profile.jpg
  35. 18 6
      src/layout/components/header.vue
  36. 3 2
      src/layout/components/nav.vue
  37. 23 11
      src/layout/components/search.vue
  38. 2 2
      src/layout/index.vue
  39. 1 1
      src/router/index.ts
  40. 16 0
      src/store/modules/station.ts
  41. 100 11
      src/views/cart/index.vue
  42. 35 0
      src/views/home/diy copy.vue
  43. 57 27
      src/views/home/diy.vue
  44. 164 24
      src/views/home/index-data.vue
  45. 151 34
      src/views/home/index-fuli.vue
  46. 124 27
      src/views/home/index-mro.vue
  47. 4 4
      src/views/home/index.vue
  48. 153 0
      src/views/home/pccomponents/index.ts
  49. 174 0
      src/views/home/pccomponents/pages/activity.vue
  50. 181 0
      src/views/home/pccomponents/pages/advert.vue
  51. 194 0
      src/views/home/pccomponents/pages/article.vue
  52. 179 0
      src/views/home/pccomponents/pages/brand.vue
  53. 121 0
      src/views/home/pccomponents/pages/carousel.vue
  54. 450 0
      src/views/home/pccomponents/pages/discover.vue
  55. 253 0
      src/views/home/pccomponents/pages/floor.vue
  56. 269 0
      src/views/home/pccomponents/pages/goods.vue
  57. 285 0
      src/views/home/pccomponents/pages/goodsList.vue
  58. 970 0
      src/views/home/pccomponents/pages/head.vue
  59. 89 0
      src/views/home/pccomponents/pages/hot.vue
  60. 102 0
      src/views/home/pccomponents/pages/imageCube.vue
  61. 160 0
      src/views/home/pccomponents/pages/navigation.vue
  62. 465 0
      src/views/home/pccomponents/pages/textTitle.vue
  63. 2 0
      src/views/home/theme.vue
  64. 25 15
      src/views/item/index.vue
  65. 10 1
      src/views/payc/index.vue
  66. 5 21
      src/views/search/brand.vue
  67. 17 1
      src/views/trad/index.vue

+ 10 - 0
src/api/home/diy.ts

@@ -35,3 +35,13 @@ export function getServiceCaseList(query: any) {
     params: query
     params: query
   });
   });
 }
 }
+
+//获取大客户站点首页diy装修页面
+
+export function getBigCustomerPlatformIndexDiyPcPage(query: any) {
+  return request({
+    url: '/mall/indexDiyPcPage/getBigCustomerPlatformIndexDiyPcPage',
+    method: 'get',
+    params: query
+  });
+}

+ 9 - 0
src/api/home/index.ts

@@ -217,3 +217,12 @@ export function countOrder(query: any) {
     params: query
     params: query
   });
   });
 }
 }
+
+//搜索栏下面的文字
+export function getSearchTitle(query: any) {
+  return request({
+    url: '/system/indexSystem/getSearchTitle',
+    method: 'get',
+    params: query
+  });
+}

BIN
src/assets/images/figure.png


BIN
src/assets/images/pcdiy/brand1.png


BIN
src/assets/images/pcdiy/code.png


BIN
src/assets/images/pcdiy/floor1.png


BIN
src/assets/images/pcdiy/floor2.png


BIN
src/assets/images/pcdiy/layout2.png


BIN
src/assets/images/pcdiy/layout4.png


BIN
src/assets/images/pcdiy/logo1.png


BIN
src/assets/images/pcdiy/logo2.png


BIN
src/assets/images/pcdiy/style10-1.png


BIN
src/assets/images/pcdiy/style10-2.png


BIN
src/assets/images/pcdiy/style11-1.png


BIN
src/assets/images/pcdiy/style11-2.png


BIN
src/assets/images/pcdiy/style11-3.png


BIN
src/assets/images/pcdiy/style13-1.png


BIN
src/assets/images/pcdiy/style13-2.png


BIN
src/assets/images/pcdiy/titlle1.png


BIN
src/assets/images/pcdiy/titlle10.png


BIN
src/assets/images/pcdiy/titlle11.png


BIN
src/assets/images/pcdiy/titlle12.png


BIN
src/assets/images/pcdiy/titlle13.png


BIN
src/assets/images/pcdiy/titlle14.png


BIN
src/assets/images/pcdiy/titlle15.png


BIN
src/assets/images/pcdiy/titlle2.png


BIN
src/assets/images/pcdiy/titlle3.png


BIN
src/assets/images/pcdiy/titlle4.png


BIN
src/assets/images/pcdiy/titlle5.png


BIN
src/assets/images/pcdiy/titlle6.png


BIN
src/assets/images/pcdiy/titlle7.png


BIN
src/assets/images/pcdiy/titlle8.png


BIN
src/assets/images/pcdiy/titlle9.png


BIN
src/assets/profile.jpg


+ 18 - 6
src/layout/components/header.vue

@@ -2,21 +2,31 @@
   <!-- 头部组件 -->
   <!-- 头部组件 -->
   <div class="header flex-row-center">
   <div class="header flex-row-center">
     <div class="header-bos flex-row-between">
     <div class="header-bos flex-row-between">
-      <div class="positioning flex-row-start">
-        <img src="@/assets/images/layout/layout1.png" alt="" />
-        <div>武汉</div>
+      <div class="flex-row-start mr-[20px]">
+        <div class="positioning flex-row-start" @click="onPath('/')">
+          <el-icon size="20"><HomeFilled /></el-icon>
+          <div class="ml-[10px]">首页</div>
+        </div>
+        <div class="positioning flex-row-start ml-[20px]">
+          <img src="@/assets/images/layout/layout1.png" alt="" />
+          <div>武汉</div>
+        </div>
       </div>
       </div>
+
       <div class="header-box flex-row-start">
       <div class="header-box flex-row-start">
         <el-dropdown v-if="userInfo.nickName">
         <el-dropdown v-if="userInfo.nickName">
-          <div class="dropdow header-text hig">{{ userInfo.nickName }}</div>
+          <div class="dropdow header-text hig">
+            {{ userInfo.nickName }}
+            <el-icon><ArrowDown /></el-icon>
+          </div>
           <template #dropdown>
           <template #dropdown>
             <el-dropdown-menu>
             <el-dropdown-menu>
               <el-dropdown-item>
               <el-dropdown-item>
                 <span>姓名:{{ userInfo.nickName }}</span>
                 <span>姓名:{{ userInfo.nickName }}</span>
               </el-dropdown-item>
               </el-dropdown-item>
               <el-dropdown-item>
               <el-dropdown-item>
-                <span>部门:</span>
-                <span class="hig">中国南方电网有</span>
+                <span>公司名字:</span>
+                <span class="hig">{{ userInfo.companyName }}</span>
               </el-dropdown-item>
               </el-dropdown-item>
               <el-dropdown-item divided @click="onlogout">退出登录</el-dropdown-item>
               <el-dropdown-item divided @click="onlogout">退出登录</el-dropdown-item>
             </el-dropdown-menu>
             </el-dropdown-menu>
@@ -49,6 +59,7 @@ onMounted(() => {
     getInfo().then((res) => {
     getInfo().then((res) => {
       if (res.code == 200) {
       if (res.code == 200) {
         userInfo.value = res.data.user;
         userInfo.value = res.data.user;
+        userInfo.value.companyName = res.data.companyName || '';
       }
       }
     });
     });
   }
   }
@@ -89,6 +100,7 @@ const onlogout = () => {
       font-weight: 400;
       font-weight: 400;
       font-size: 14px;
       font-size: 14px;
       color: #322b2b;
       color: #322b2b;
+      cursor: pointer;
       img {
       img {
         height: 20px;
         height: 20px;
         width: 20px;
         width: 20px;

+ 3 - 2
src/layout/components/nav.vue

@@ -6,7 +6,7 @@
         <img src="@/assets/images/layout/layout2.png" alt="" />
         <img src="@/assets/images/layout/layout2.png" alt="" />
         <div>全部商品分类</div>
         <div>全部商品分类</div>
       </div>
       </div>
-      <div @click="onPath(item.url)" v-for="(item, index) in navList" :key="index" class="nav-list" :class="item.url == route.path ? 'hig' : ''">
+      <div @click="onPath(item.url)" v-for="(item, index) in navList" :key="index" class="nav-list" :class="item.url == route.fullPath ? 'hig' : ''">
         {{ item.title }}
         {{ item.title }}
       </div>
       </div>
       <div class="nav-classify" v-if="classifyOpen" @mouseleave="leaveClassify">
       <div class="nav-classify" v-if="classifyOpen" @mouseleave="leaveClassify">
@@ -47,6 +47,7 @@ import { onPath } from '@/utils/siteConfig';
 import { categoryStore } from '@/store/modules/category';
 import { categoryStore } from '@/store/modules/category';
 const categoryStoreStore = categoryStore();
 const categoryStoreStore = categoryStore();
 const route = useRoute();
 const route = useRoute();
+console.log(route, '8888');
 const classifyList = ref<any>([]);
 const classifyList = ref<any>([]);
 const classifyOpen = ref<any>(false);
 const classifyOpen = ref<any>(false);
 const classifyShow = ref<any>(false);
 const classifyShow = ref<any>(false);
@@ -56,7 +57,7 @@ const navList = ref<any>([
   { title: '首页', url: '/index' },
   { title: '首页', url: '/index' },
   { title: '工业品商城', url: '/indexMro' },
   { title: '工业品商城', url: '/indexMro' },
   { title: '福礼商城', url: '/indexFuli' },
   { title: '福礼商城', url: '/indexFuli' },
-  { title: '商用工程' },
+  { title: '商用工程', url: '/theme?id=2' },
   { title: '场景采购', url: '/plan/procure' },
   { title: '场景采购', url: '/plan/procure' },
   { title: '解决方案', url: '/plan' },
   { title: '解决方案', url: '/plan' },
   { title: '特价专区', url: '/search/special' }
   { title: '特价专区', url: '/search/special' }

+ 23 - 11
src/layout/components/search.vue

@@ -23,7 +23,14 @@
           </div>
           </div>
         </div>
         </div>
         <div class="search-text">
         <div class="search-text">
-          <div v-for="(item, index) in toplabel" :key="index">{{ item.title }}</div>
+          <div
+            @click="onPath('/search?type=1&input=' + item.navigationName)"
+            v-for="(item, index) in toplabel"
+            :key="index"
+            :class="{ 'hig': index == 0 }"
+          >
+            {{ item.navigationName }}
+          </div>
         </div>
         </div>
       </div>
       </div>
       <img class="code" src="@/assets/images/code.png" alt="" />
       <img class="code" src="@/assets/images/code.png" alt="" />
@@ -34,25 +41,24 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import { onPath } from '@/utils/siteConfig';
 import { onPath } from '@/utils/siteConfig';
 import { cartStore } from '@/store/modules/cart';
 import { cartStore } from '@/store/modules/cart';
+import { getSearchTitle } from '@/api/home/index';
 const cartStoreData = cartStore();
 const cartStoreData = cartStore();
 const cartCount = computed(() => cartStoreData.cartCount);
 const cartCount = computed(() => cartStoreData.cartCount);
 const input = ref<any>('');
 const input = ref<any>('');
 const route = useRoute();
 const route = useRoute();
 const meta = ref<any>({});
 const meta = ref<any>({});
-const toplabel = ref<any>([
-  { title: '家纺', url: '' },
-  { title: '打印机', url: '' },
-  { title: '打印耗材', url: '' },
-  { title: '空调', url: '' },
-  { title: '取暖', url: '' },
-  { title: '开门红', url: '' },
-  { title: '劳保福利', url: '' }
-]);
+const toplabel = ref<any>([]);
 meta.value = route.meta;
 meta.value = route.meta;
 
 
 watch(route, () => {
 watch(route, () => {
   meta.value = route.meta;
   meta.value = route.meta;
 });
 });
+
+getSearchTitle({}).then((res) => {
+  if (res.code == 200) {
+    toplabel.value = res.data;
+  }
+});
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
@@ -134,13 +140,19 @@ watch(route, () => {
 
 
     .search-text {
     .search-text {
       font-size: 12px;
       font-size: 12px;
-      color: #e7000b;
       display: flex;
       display: flex;
       margin-top: 4px;
       margin-top: 4px;
       cursor: pointer;
       cursor: pointer;
 
 
+      .hig {
+        color: #e7000b;
+      }
+
       div {
       div {
         margin-left: 10px;
         margin-left: 10px;
+        &:hover {
+          color: #e7000b;
+        }
       }
       }
     }
     }
   }
   }

+ 2 - 2
src/layout/index.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <div class="app-wrapper">
   <div class="app-wrapper">
     <Header v-if="meta.header != 'hide'" />
     <Header v-if="meta.header != 'hide'" />
-    <Search v-if="meta.header != 'hide'" />
+    <Search v-if="meta.search != 'hide'" />
     <Nav v-if="meta.nav" />
     <Nav v-if="meta.nav" />
     <Breadcrumb v-if="meta.breadcrumb" />
     <Breadcrumb v-if="meta.breadcrumb" />
     <div class="pages-bos" :class="meta.workbench ? 'pages-bos1' : 'pages-bos2'">
     <div class="pages-bos" :class="meta.workbench ? 'pages-bos1' : 'pages-bos2'">
@@ -45,7 +45,7 @@ watch(route, () => {
       width: 100%;
       width: 100%;
     }
     }
 
 
-    .page-container{
+    .page-container {
       flex: 1;
       flex: 1;
       background-color: #ffffff;
       background-color: #ffffff;
       padding: 15px;
       padding: 15px;

+ 1 - 1
src/router/index.ts

@@ -90,7 +90,7 @@ export const constantRoutes: RouteRecordRaw[] = [
         path: '/diy',
         path: '/diy',
         component: () => import('@/views/home/diy.vue'),
         component: () => import('@/views/home/diy.vue'),
         name: 'IndexDiy',
         name: 'IndexDiy',
-        meta: { title: 'Diy商城', icon: 'dashboard', affix: true, nav: true }
+        meta: { title: 'Diy商城', diy: true, search: 'hide' }
       },
       },
       {
       {
         path: '/theme',
         path: '/theme',

+ 16 - 0
src/store/modules/station.ts

@@ -0,0 +1,16 @@
+import { getSiteAddress } from '@/api/home/index-data';
+
+export const stationStore = defineStore('station', () => {
+  const stationData = ref<any>({});
+
+  const onstation = async () => {
+    const res = await getSiteAddress({});
+    stationData.value = res.data;
+    return res.data;
+  };
+
+  return {
+    stationData,
+    onstation
+  };
+});

+ 100 - 11
src/views/cart/index.vue

@@ -9,6 +9,7 @@
         <div class="head2">导出订单</div>
         <div class="head2">导出订单</div>
       </div>
       </div>
       <el-table
       <el-table
+        ref="multipleTableRef"
         :data="tableData"
         :data="tableData"
         style="width: 100%"
         style="width: 100%"
         :header-cell-style="{
         :header-cell-style="{
@@ -37,7 +38,7 @@
         </el-table-column>
         </el-table-column>
         <el-table-column label="数量" width="200">
         <el-table-column label="数量" width="200">
           <template #default="scope">
           <template #default="scope">
-            <el-input-number v-model="scope.row.productNum" :min="1" :max="10" />
+            <el-input-number v-model="scope.row.productNum" :min="1" :max="scope.row.allStock" @change="(res) => handleChange(res, scope.row)" />
           </template>
           </template>
         </el-table-column>
         </el-table-column>
         <el-table-column label="小计" width="140">
         <el-table-column label="小计" width="140">
@@ -46,7 +47,7 @@
         <el-table-column label="操作">
         <el-table-column label="操作">
           <template #default="scope">
           <template #default="scope">
             <div>
             <div>
-              <el-button link> 移入收藏 </el-button>
+              <el-button @click="editCollection(scope.row)" link>{{ scope.row.isCollect == 1 ? '取消收藏' : '移入收藏' }} </el-button>
             </div>
             </div>
             <div>
             <div>
               <el-button link @click="onDel(scope.row)"> 删除 </el-button>
               <el-button link @click="onDel(scope.row)"> 删除 </el-button>
@@ -77,7 +78,7 @@
                 <div class="text2">
                 <div class="text2">
                   <span>单位:{{ scope.row.unitName }}</span>
                   <span>单位:{{ scope.row.unitName }}</span>
                 </div>
                 </div>
-                <div class="text3">当前商品库存不足,当前库存量:999把</div>
+                <div class="text3">当前商品库存不足,当前库存量:0</div>
               </div>
               </div>
             </div>
             </div>
           </template>
           </template>
@@ -96,7 +97,7 @@
         <el-table-column label="操作">
         <el-table-column label="操作">
           <template #default="scope">
           <template #default="scope">
             <div>
             <div>
-              <el-button link> 移入收藏 </el-button>
+              <el-button @click="editCollection(scope.row)" link>{{ scope.row.isCollect == 1 ? '取消收藏' : '移入收藏' }} </el-button>
             </div>
             </div>
             <div>
             <div>
               <el-button link @click="onDel(scope.row)"> 删除 </el-button>
               <el-button link @click="onDel(scope.row)"> 删除 </el-button>
@@ -107,11 +108,12 @@
     </div>
     </div>
     <div class="cart-bnt">
     <div class="cart-bnt">
       <div class="bnt-bos flex-row-between">
       <div class="bnt-bos flex-row-between">
-        <div class="flex-row-start">
-          <el-checkbox v-model="checked1" label="全选" />
+        <div></div>
+        <!-- <div class="flex-row-start">
+          <el-checkbox v-model="checked1" label="全选" @change="handleSelectAll" />
           <el-button style="margin-left: 10px">删除</el-button>
           <el-button style="margin-left: 10px">删除</el-button>
           <el-button>移入收藏</el-button>
           <el-button>移入收藏</el-button>
-        </div>
+        </div> -->
         <div class="bnt-box flex-row-start">
         <div class="bnt-box flex-row-start">
           <span>共</span>
           <span>共</span>
           <span class="hig">{{ tableData.length }}</span>
           <span class="hig">{{ tableData.length }}</span>
@@ -126,17 +128,51 @@
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>
+    <!-- 取消收藏 -->
+    <el-dialog
+      v-model="dialogVisible"
+      title="选择取消的收藏夹"
+      width="500"
+      :before-close="
+        () => {
+          dialogVisible = false;
+        }
+      "
+    >
+      <div>
+        <el-radio-group v-model="radio">
+          <el-radio v-for="(item, index) in favorites" :key="index" :value="item.id">{{ item.title }}</el-radio>
+        </el-radio-group>
+      </div>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="onCancel"> 确认 </el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
+import type { TableInstance } from 'element-plus';
 const tableData = ref<any>([]);
 const tableData = ref<any>([]);
 const selectedList = ref<any>([]);
 const selectedList = ref<any>([]);
 const noTableData = ref<any>([]);
 const noTableData = ref<any>([]);
-
+const multipleTableRef = ref<TableInstance>();
 const checked1 = ref(false);
 const checked1 = ref(false);
-
-import { shoppingCartList, deleteProductShoppingCart } from '@/api/goods/index';
+const dialogVisible = ref<any>(false);
+const favorites = ref<any>([]);
+const radio = ref<any>(null);
+const radioRow = ref<any>({});
+import {
+  shoppingCartList,
+  deleteProductShoppingCart,
+  isProductInDefaultCollect,
+  cancelProductCollect,
+  addProductCollect,
+  favoritesList
+} from '@/api/goods/index';
 import { onPath } from '@/utils/siteConfig';
 import { onPath } from '@/utils/siteConfig';
 
 
 onMounted(() => {
 onMounted(() => {
@@ -150,7 +186,9 @@ const getInfo = () => {
       noTableData.value = [];
       noTableData.value = [];
       if (res.rows && res.rows.length > 0) {
       if (res.rows && res.rows.length > 0) {
         res.rows.forEach((item: any) => {
         res.rows.forEach((item: any) => {
-          if (item.productStatus == 1) {
+          item.allStock = Number(item.totalInventory || 0) + Number(item.nowInventory || 0) + Number(item.virtualInventory || 0);
+          // item.allStock = 8888;
+          if (item.productStatus == 1 && item.allStock > 0) {
             tableData.value.push(item);
             tableData.value.push(item);
           } else {
           } else {
             noTableData.value.push(item);
             noTableData.value.push(item);
@@ -161,11 +199,28 @@ const getInfo = () => {
   });
   });
 };
 };
 
 
+const handleChange = (val: any, row: any) => {
+  const numberVal = Number(val);
+  const step = row.minOrderQuantity || 1;
+  row.productNum = Math.ceil(numberVal / step) * step;
+};
+
 //购物车选中
 //购物车选中
 const handleSelectionChange1 = (val: any) => {
 const handleSelectionChange1 = (val: any) => {
   selectedList.value = val;
   selectedList.value = val;
 };
 };
 
 
+//全选
+const handleSelectAll = (val: any) => {
+  if (val) {
+    multipleTableRef.value?.toggleAllSelection();
+  } else {
+    multipleTableRef.value?.clearSelection();
+  }
+};
+
+import { cartStore } from '@/store/modules/cart';
+const cart = cartStore();
 const onDel = (row: any) => {
 const onDel = (row: any) => {
   ElMessageBox.confirm(`确定要删除吗?`, '提示', {
   ElMessageBox.confirm(`确定要删除吗?`, '提示', {
     confirmButtonText: '确定',
     confirmButtonText: '确定',
@@ -176,6 +231,7 @@ const onDel = (row: any) => {
       if (res.code == 200) {
       if (res.code == 200) {
         ElMessage.success('删除成功');
         ElMessage.success('删除成功');
         getInfo();
         getInfo();
+        cart.onCartCount();
       }
       }
     });
     });
   });
   });
@@ -199,6 +255,39 @@ const onMoney = computed(() => {
   price = Number(money).toFixed(2);
   price = Number(money).toFixed(2);
   return price;
   return price;
 });
 });
+
+//修改收藏
+const editCollection = (row: any) => {
+  if (row.isCollect == 1) {
+    dialogVisible.value = true;
+    favoritesList(row.id).then((res) => {
+      if (res.code == 200) {
+        if (res.rows.length > 0) {
+          radio.value = res.rows[0].id;
+        }
+        favorites.value = res.rows;
+        radioRow.value = row;
+      }
+    });
+  } else {
+    // 添加
+    addProductCollect({ productId: row.id }).then((res) => {
+      if (res.code == 200) {
+        getInfo();
+      }
+    });
+  }
+};
+
+// 取消收藏
+const onCancel = () => {
+  cancelProductCollect({ productId: radioRow.value.id, favoritesId: radio.value }).then((res) => {
+    if (res.code == 200) {
+      dialogVisible.value = false;
+      getInfo();
+    }
+  });
+};
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>

+ 35 - 0
src/views/home/diy copy.vue

@@ -0,0 +1,35 @@
+<template>
+  <div class="pay-pages"></div>
+</template>
+
+<script setup lang="ts">
+import { getAnnouncementPage, getDiyProductPage, getServiceCaseList, getPlatformIndexDiyPcPage } from '@/api/home/diy';
+
+getAnnouncementPage({
+  pageNum: 1,
+  pageSize: 10,
+  ids: '1,2,3'
+}).then((res) => {
+  if (res.code == 200) {
+    // carouselList.value = res.data;
+  }
+});
+getDiyProductPage({ pageNum: 1, pageSize: 10, ids: '434643,434645' }).then((res) => {
+  if (res.code == 200) {
+    // carouselList.value = res.data;
+  }
+});
+getServiceCaseList({ pageNum: 1, pageSize: 10, ids: '1031,1032' }).then((res) => {
+  if (res.code == 200) {
+    // carouselList.value = res.data;
+  }
+});
+
+getPlatformIndexDiyPcPage({}).then((res) => {
+  if (res.code == 200) {
+    // carouselList.value = res.data;
+  }
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 57 - 27
src/views/home/diy.vue

@@ -1,35 +1,65 @@
 <template>
 <template>
-  <div class="pay-pages"></div>
+  <div class="pcdiys-pages" :style="{ backgroundColor: componentList.backgroundColor }">
+    <div v-for="(item, index) in componentList" :key="index">
+      <component :is="item.components" :key="item.itemKey" :index="index" :row="item"></component>
+    </div>
+  </div>
 </template>
 </template>
 
 
-<script setup lang="ts">
-import { getAnnouncementPage, getDiyProductPage, getServiceCaseList,getPlatformIndexDiyPcPage } from '@/api/home/diy';
+<script setup name="Index" lang="ts">
+import { getBigCustomerPlatformIndexDiyPcPage } from '@/api/home/diy';
+import { loadDiyComponents, getComponentGroups } from '@/views/home/pccomponents/index';
+import { stationStore } from '@/store/modules/station';
+const station = stationStore();
+const componentList = ref<any>([]);
+const collapse = ref<any>([]);
+const route = useRoute();
+const query = route.query;
+const formData = ref<any>({});
 
 
-getAnnouncementPage({
-  pageNum: 1,
-  pageSize: 10,
-  ids: '1,2,3'
-}).then((res) => {
-  if (res.code == 200) {
-    // carouselList.value = res.data;
-  }
-});
-getDiyProductPage({ pageNum: 1, pageSize: 10, ids: '434643,434645' }).then((res) => {
-  if (res.code == 200) {
-    // carouselList.value = res.data;
-  }
-});
-getServiceCaseList({ pageNum: 1, pageSize: 10, ids: '1031,1032' }).then((res) => {
-  if (res.code == 200) {
-    // carouselList.value = res.data;
-  }
+onMounted(() => {
+  loadComponents();
 });
 });
 
 
-getPlatformIndexDiyPcPage({}).then((res) => {
-  if (res.code == 200) {
-    // carouselList.value = res.data;
-  }
-});
+// 加载组件
+const loadComponents = async () => {
+  const components = await loadDiyComponents();
+  collapse.value = getComponentGroups(components);
+  getBigCustomerPlatformIndexDiyPcPage({ siteId: station.stationData.id }).then((res) => {
+    if (res.code == 200) {
+      formData.value = res.data;
+      document.documentElement.style.setProperty('--hover-color', res.data.hoverColor ? res.data.hoverColor : '#E7000B');
+      const datas = JSON.parse(res.data.property);
+      collapse.value.forEach((item1: any) => {
+        datas.forEach((item2: any) => {
+          if (item1.id == item2.fid) {
+            item1.list.forEach((item3: any) => {
+              if (item2.id == item3.id) {
+                item2.components = item3.components;
+              }
+            });
+          }
+        });
+      });
+      componentList.value = datas;
+    }
+  });
+};
 </script>
 </script>
 
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.pcdiys-pages {
+  min-height: calc(100vh);
+  background-color: #f2f2f2;
+  width: 100%;
+  :deep(.hover-color) {
+    cursor: pointer;
+    &:hover {
+      color: var(--hover-color) !important;
+      .zi-hover {
+        color: var(--hover-color) !important;
+      }
+    }
+  }
+}
+</style>

+ 164 - 24
src/views/home/index-data.vue

@@ -46,7 +46,40 @@
       </div>
       </div>
       <!-- 右边 -->
       <!-- 右边 -->
       <div class="head-right">
       <div class="head-right">
-        <div class="login-bos">
+        <div v-if="userInfo.userId" class="order-bos flex-column-between">
+          <div class="flex-row-start">
+            <img src="@/assets/images/logo2.png" alt="" />
+            <div class="ellipsis">{{ userInfo.nickName }}</div>
+          </div>
+          <div class="flex-row-start">
+            <div class="flex-1 flex-column-center">
+              <div>待付款</div>
+              <div class="order-num">{{ countData.pendingPaymentCount || 0 }}</div>
+            </div>
+            <div class="flex-1 flex-column-center">
+              <div>待发货</div>
+              <div class="order-num">{{ countData.pendingShipmentCount || 0 }}</div>
+            </div>
+            <div class="flex-1 flex-column-center">
+              <div>待收货</div>
+              <div class="order-num">{{ countData.pendingReceiptCount || 0 }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="login-bos" v-else>
+          <div class="login-box">
+            <img src="@/assets/images/logo2.png" alt="" />
+            <div>
+              <div class="login1">您好,欢迎来到优易达</div>
+              <div class="login2">请先登录</div>
+            </div>
+          </div>
+          <div class="loginBtn-bos flex-row-center">
+            <div @click="onPath('/login')" class="login-bnt1 flex-row-center">登录</div>
+            <div @click="onPath('/breg')" class="login-bnt2 flex-row-center">注册</div>
+          </div>
+        </div>
+        <!-- <div class="login-bos">
           <div class="login-box">
           <div class="login-box">
             <img :src="userInfo.avatar ? userInfo.avatar : profile" alt="" />
             <img :src="userInfo.avatar ? userInfo.avatar : profile" alt="" />
             <div>
             <div>
@@ -59,15 +92,15 @@
             <el-button v-if="!userInfo.nickName" type="primary" plain round size="small" style="width: 64px">注册</el-button>
             <el-button v-if="!userInfo.nickName" type="primary" plain round size="small" style="width: 64px">注册</el-button>
             <el-button v-if="userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onlogout()">退出</el-button>
             <el-button v-if="userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onlogout()">退出</el-button>
           </div>
           </div>
-        </div>
+        </div> -->
         <div class="real-time">
         <div class="real-time">
           <div class="real-title flex-row-between">
           <div class="real-title flex-row-between">
             <div class="real1">优易资讯</div>
             <div class="real1">优易资讯</div>
             <div class="real2 flex-row-start">
             <div class="real2 flex-row-start">
-              <div>更多</div>
+              <!-- <div>更多</div>
               <el-icon :size="13" color="#83899F">
               <el-icon :size="13" color="#83899F">
                 <ArrowRight />
                 <ArrowRight />
-              </el-icon>
+              </el-icon> -->
             </div>
             </div>
           </div>
           </div>
           <template v-for="(item, index) in realList" :key="index">
           <template v-for="(item, index) in realList" :key="index">
@@ -97,7 +130,7 @@
         <img class="goods-one" :src="item.imageUrl" alt="" />
         <img class="goods-one" :src="item.imageUrl" alt="" />
         <div class="goods-shop">
         <div class="goods-shop">
           <template v-for="(item1, index1) in item.goodsList" :key="index1">
           <template v-for="(item1, index1) in item.goodsList" :key="index1">
-            <div v-if="Number(index1) < 8" class="shop-list flex-column-between">
+            <div v-if="Number(index1) < 8" class="shop-list flex-column-between" @click="onPath('/item?id=' + item1.id)">
               <img class="shop-img" :src="item1.productImage ? item1.productImage.split(',')[0] : ''" alt="" />
               <img class="shop-img" :src="item1.productImage ? item1.productImage.split(',')[0] : ''" alt="" />
               <div class="shop-name ellipsis2">{{ item1.itemName || '' }}</div>
               <div class="shop-name ellipsis2">{{ item1.itemName || '' }}</div>
               <div class="shop-price">
               <div class="shop-price">
@@ -166,11 +199,12 @@ import {
   getClassificationFloorLabel,
   getClassificationFloorLabel,
   getClassificationFloorDetail2,
   getClassificationFloorDetail2,
   getProjectCaseTitle,
   getProjectCaseTitle,
-  getProjectCaseList
+  getProjectCaseList,
+  countOrder
 } from '@/api/home/index';
 } from '@/api/home/index';
 
 
 import { getSiteFloorList, getSiteAddress, getSiteFloorProductList, getSiteFloorBrandList, getSiteProductList } from '@/api/home/index-data';
 import { getSiteFloorList, getSiteAddress, getSiteFloorProductList, getSiteFloorBrandList, getSiteProductList } from '@/api/home/index-data';
-
+import Cookies from 'js-cookie';
 const userInfo = ref<any>({});
 const userInfo = ref<any>({});
 const classifyList = ref<any>([]);
 const classifyList = ref<any>([]);
 const classifyShow = ref<any>(false);
 const classifyShow = ref<any>(false);
@@ -183,15 +217,15 @@ const AdList = ref<any>([]);
 const hotTitle = ref<any>('');
 const hotTitle = ref<any>('');
 const sceneTitle = ref<any>('');
 const sceneTitle = ref<any>('');
 const expertTitle = ref<any>('');
 const expertTitle = ref<any>('');
-const expertList = ref<any>([{}, {}, {}, {}, {}]);
+const expertList = ref<any>([]);
 const procureTitle = ref<any>('');
 const procureTitle = ref<any>('');
-const procureList = ref<any>([{}, {}, {}, {}, {}]);
+const procureList = ref<any>([]);
 const projectTitle = ref<any>('');
 const projectTitle = ref<any>('');
-const projectList = ref<any>([{}, {}, {}, {}, {}]);
+const projectList = ref<any>([]);
 
 
 const bigbrandTitle = ref<any>('');
 const bigbrandTitle = ref<any>('');
 const bigbrandOne = ref<any>({});
 const bigbrandOne = ref<any>({});
-
+const countData = ref<any>({});
 const goodsList = ref<any>([]);
 const goodsList = ref<any>([]);
 const recommendList = ref<any>([]);
 const recommendList = ref<any>([]);
 
 
@@ -205,10 +239,17 @@ getSiteAddress({}).then((res) => {
 });
 });
 
 
 onMounted(() => {
 onMounted(() => {
-  if (getToken()) {
+  const token = Cookies.get('Authorization');
+  if (token) {
     getInfo().then((res) => {
     getInfo().then((res) => {
       if (res.code == 200) {
       if (res.code == 200) {
         userInfo.value = res.data.user;
         userInfo.value = res.data.user;
+
+        countOrder({}).then((res1) => {
+          if (res1.code == 200) {
+            countData.value = res1.data || {};
+          }
+        });
       }
       }
     });
     });
   }
   }
@@ -436,21 +477,21 @@ const onlogout = () => {
 
 
     // 头部中间
     // 头部中间
     .head-bos {
     .head-bos {
-      width: 756px;
+      flex: 1;
 
 
       .carousel {
       .carousel {
-        width: 756px;
+        width: 100%;
         height: 407px;
         height: 407px;
         background: #ffffff;
         background: #ffffff;
 
 
         img {
         img {
-          width: 756px;
+          width: 100%;
           height: 407px;
           height: 407px;
         }
         }
       }
       }
 
 
       .head-box {
       .head-box {
-        width: 756px;
+        width: 100%;
         height: 122px;
         height: 122px;
         margin-top: 10px;
         margin-top: 10px;
         display: flex;
         display: flex;
@@ -470,6 +511,28 @@ const onlogout = () => {
           img {
           img {
             width: 100%;
             width: 100%;
             height: 100%;
             height: 100%;
+            // width: 84px;
+            // height: 84px;
+            // margin-right: 10px;
+            // border-radius: 10px;
+          }
+
+          .head-title {
+            .head1 {
+              font-weight: 550;
+              font-size: 22px;
+              color: #101828;
+            }
+
+            .head2 {
+              width: 76px;
+              height: 21px;
+              border-radius: 34px;
+              border: 1px solid #000000;
+              font-size: 12px;
+              color: #000000;
+              margin-top: 6px;
+            }
           }
           }
         }
         }
       }
       }
@@ -477,8 +540,7 @@ const onlogout = () => {
 
 
     //右边
     //右边
     .head-right {
     .head-right {
-      flex: 1;
-      width: 0;
+      width: 230px;
       height: 540px;
       height: 540px;
       background: #ffffff;
       background: #ffffff;
       display: flex;
       display: flex;
@@ -505,10 +567,6 @@ const onlogout = () => {
             border-radius: 40px;
             border-radius: 40px;
           }
           }
 
 
-          .login-btn {
-            width: 100%;
-          }
-
           .login1 {
           .login1 {
             font-size: 13px;
             font-size: 13px;
             color: #444444;
             color: #444444;
@@ -520,6 +578,87 @@ const onlogout = () => {
             color: #6a7282;
             color: #6a7282;
           }
           }
         }
         }
+
+        .loginBtn-bos {
+          width: 100%;
+
+          .login-bnt1 {
+            width: 64px;
+            height: 24px;
+            background-color: #e7000b;
+            color: #ffffff;
+            border-radius: 24px;
+            font-size: 12px;
+            cursor: pointer;
+          }
+
+          .login-bnt2 {
+            width: 64px;
+            height: 24px;
+            border: 1px solid #e7000b;
+            color: #e7000b;
+            border-radius: 24px;
+            font-size: 12px;
+            margin-left: 10px;
+            cursor: pointer;
+          }
+        }
+      }
+
+      // .login-bos {
+      //   width: calc(100% - 20px);
+      //   height: 110px;
+      //   border-bottom: 1px solid #e5e7eb;
+      //   margin: 0 10px;
+      //   display: flex;
+      //   flex-direction: column;
+      //   justify-content: space-between;
+      //   padding: 16px 0;
+
+      //   .login-box {
+      //     display: flex;
+      //     align-items: center;
+
+      //     img {
+      //       width: 40px;
+      //       height: 40px;
+      //       margin-right: 8px;
+      //       border-radius: 40px;
+      //     }
+
+      //     .login-btn {
+      //       width: 100%;
+      //     }
+
+      //     .login1 {
+      //       font-size: 13px;
+      //       color: #444444;
+      //     }
+
+      //     .login2 {
+      //       margin-top: 2px;
+      //       font-size: 12px;
+      //       color: #6a7282;
+      //     }
+      //   }
+      // }
+
+      .order-bos {
+        width: calc(100% - 20px);
+        height: 110px;
+        font-size: 14px;
+        padding: 16px 0;
+        border-bottom: 1px solid #e5e7eb;
+        margin: 0 10px;
+        img {
+          width: 28px;
+          height: 28px;
+        }
+        .order-num {
+          color: #e7000b;
+          font-size: 14px;
+          margin-top: 2px;
+        }
       }
       }
 
 
       .real-time {
       .real-time {
@@ -559,7 +698,7 @@ const onlogout = () => {
 
 
         .real-list {
         .real-list {
           width: 100%;
           width: 100%;
-          font-size: 14px;
+          font-size: 12px;
           color: #1d2129;
           color: #1d2129;
           margin-bottom: 12px;
           margin-bottom: 12px;
           cursor: pointer;
           cursor: pointer;
@@ -767,9 +906,10 @@ const onlogout = () => {
   .sell-bos {
   .sell-bos {
     width: 1200px;
     width: 1200px;
     display: flex;
     display: flex;
-    gap: 0 20px;
+    gap: 15px 20px;
     margin-top: 15px;
     margin-top: 15px;
     padding-bottom: 30px;
     padding-bottom: 30px;
+    flex-wrap: wrap;
 
 
     .sell-list {
     .sell-list {
       width: 224px;
       width: 224px;

+ 151 - 34
src/views/home/index-fuli.vue

@@ -40,34 +40,65 @@
         </div>
         </div>
         <!-- 右边 -->
         <!-- 右边 -->
         <div class="head-right">
         <div class="head-right">
-          <div class="login-bos">
+          <div v-if="userInfo.userId" class="order-bos flex-column-between">
+            <div class="flex-row-start">
+              <img src="@/assets/images/logo2.png" alt="" />
+              <div class="ellipsis">{{ userInfo.nickName }}</div>
+            </div>
+            <div class="flex-row-start">
+              <div class="flex-1 flex-column-center">
+                <div>待付款</div>
+                <div class="order-num">{{ countData.pendingPaymentCount || 0 }}</div>
+              </div>
+              <div class="flex-1 flex-column-center">
+                <div>待发货</div>
+                <div class="order-num">{{ countData.pendingShipmentCount || 0 }}</div>
+              </div>
+              <div class="flex-1 flex-column-center">
+                <div>待收货</div>
+                <div class="order-num">{{ countData.pendingReceiptCount || 0 }}</div>
+              </div>
+            </div>
+          </div>
+          <div class="login-bos" v-else>
             <div class="login-box">
             <div class="login-box">
-              <img :src="userInfo.avatar ? userInfo.avatar : profile" alt="" />
+              <img src="@/assets/images/logo2.png" alt="" />
               <div>
               <div>
                 <div class="login1">您好,欢迎来到优易达</div>
                 <div class="login1">您好,欢迎来到优易达</div>
-                <div class="login2">{{ userInfo.nickName ? userInfo.nickName : '请先登录' }}</div>
+                <div class="login2">请先登录</div>
               </div>
               </div>
             </div>
             </div>
-            <div class="login-btn">
-              <el-button v-if="!userInfo.nickName" type="primary" round size="small" style="width: 64px" @click="onPath('/login')">登录</el-button>
-              <el-button v-if="!userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onPath('/reg')"
-                >注册</el-button
-              >
-              <el-button v-if="userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onPath('/reg')">退出</el-button>
+            <div class="loginBtn-bos flex-row-center">
+              <div @click="onPath('/login')" class="login-bnt1 flex-row-center">登录</div>
+              <div @click="onPath('/breg')" class="login-bnt2 flex-row-center">注册</div>
+            </div>
+          </div>
+          <!-- <div class="login-bos">
+          <div class="login-box">
+            <img :src="userInfo.avatar ? userInfo.avatar : profile" alt="" />
+            <div>
+              <div class="login1">您好,欢迎来到优易达</div>
+              <div class="login2">{{ userInfo.nickName ? userInfo.nickName : '请先登录' }}</div>
             </div>
             </div>
           </div>
           </div>
+          <div class="login-btn">
+            <el-button v-if="!userInfo.nickName" type="primary" round size="small" style="width: 64px" @click="onPath('/login')">登录</el-button>
+            <el-button v-if="!userInfo.nickName" type="primary" plain round size="small" style="width: 64px">注册</el-button>
+            <el-button v-if="userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onlogout()">退出</el-button>
+          </div>
+        </div> -->
           <div class="real-time">
           <div class="real-time">
             <div class="real-title flex-row-between">
             <div class="real-title flex-row-between">
               <div class="real1">优易资讯</div>
               <div class="real1">优易资讯</div>
               <div class="real2 flex-row-start">
               <div class="real2 flex-row-start">
-                <div>更多</div>
-                <el-icon :size="13" color="#83899F">
-                  <ArrowRight />
-                </el-icon>
+                <!-- <div>更多</div>
+              <el-icon :size="13" color="#83899F">
+                <ArrowRight />
+              </el-icon> -->
               </div>
               </div>
             </div>
             </div>
             <template v-for="(item, index) in realList" :key="index">
             <template v-for="(item, index) in realList" :key="index">
-              <div class="real-list ellipsis" v-if="Number(index) < 7">{{ item.announcementTitle }}</div>
+              <div @click="onPath('/solve/real?id=' + item.id)" class="real-list ellipsis" v-if="Number(index) < 7">{{ item.announcementTitle }}</div>
             </template>
             </template>
           </div>
           </div>
           <div class="interests">
           <div class="interests">
@@ -164,19 +195,11 @@ import {
   getGiftFloorLinkProductList,
   getGiftFloorLinkProductList,
   getRecommendGiftFloorList
   getRecommendGiftFloorList
 } from '@/api/home/index-fuli';
 } from '@/api/home/index-fuli';
+import Cookies from 'js-cookie';
 
 
-import { getProductCategoryTree, getYouYiZiXunPage } from '@/api/home/index';
-
-onMounted(() => {
-  if (getToken()) {
-    getInfo().then((res) => {
-      if (res.code == 200) {
-        userInfo.value = res.data.user;
-      }
-    });
-  }
-});
+import { getProductCategoryTree, getYouYiZiXunPage, countOrder } from '@/api/home/index';
 
 
+const countData = ref<any>({});
 const userInfo = ref<any>({});
 const userInfo = ref<any>({});
 const classifyList = ref<any>([]);
 const classifyList = ref<any>([]);
 const classifyShow = ref<any>(false);
 const classifyShow = ref<any>(false);
@@ -190,6 +213,23 @@ const popular = ref<any>([]);
 const goodsList = ref<any>([]);
 const goodsList = ref<any>([]);
 const recommend = ref<any>([]);
 const recommend = ref<any>([]);
 
 
+onMounted(() => {
+  const token = Cookies.get('Authorization');
+  if (token) {
+    getInfo().then((res) => {
+      if (res.code == 200) {
+        userInfo.value = res.data.user;
+
+        countOrder({}).then((res1) => {
+          if (res1.code == 200) {
+            countData.value = res1.data || {};
+          }
+        });
+      }
+    });
+  }
+});
+
 //头部分类
 //头部分类
 getProductCategoryTree({}).then((res) => {
 getProductCategoryTree({}).then((res) => {
   if (res.code == 200) {
   if (res.code == 200) {
@@ -297,6 +337,7 @@ getRecommendGiftFloorList({}).then((res) => {
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .home-pages {
 .home-pages {
   width: 100%;
   width: 100%;
+  margin-top: 10px;
   .head-pages {
   .head-pages {
     width: 100%;
     width: 100%;
     background: #ead3ab;
     background: #ead3ab;
@@ -425,18 +466,17 @@ getRecommendGiftFloorList({}).then((res) => {
 
 
       // 头部中间
       // 头部中间
       .carousel-bos {
       .carousel-bos {
-        width: 756px;
+        flex: 1;
         height: 540px;
         height: 540px;
         img {
         img {
-          width: 756px;
+          width: 100%;
           height: 540px;
           height: 540px;
         }
         }
       }
       }
 
 
       //右边
       //右边
       .head-right {
       .head-right {
-        flex: 1;
-        width: 0;
+        width: 230px;
         height: 540px;
         height: 540px;
         background: #ffffff;
         background: #ffffff;
         display: flex;
         display: flex;
@@ -463,10 +503,6 @@ getRecommendGiftFloorList({}).then((res) => {
               border-radius: 40px;
               border-radius: 40px;
             }
             }
 
 
-            .login-btn {
-              width: 100%;
-            }
-
             .login1 {
             .login1 {
               font-size: 13px;
               font-size: 13px;
               color: #444444;
               color: #444444;
@@ -478,6 +514,87 @@ getRecommendGiftFloorList({}).then((res) => {
               color: #6a7282;
               color: #6a7282;
             }
             }
           }
           }
+
+          .loginBtn-bos {
+            width: 100%;
+
+            .login-bnt1 {
+              width: 64px;
+              height: 24px;
+              background-color: #e7000b;
+              color: #ffffff;
+              border-radius: 24px;
+              font-size: 12px;
+              cursor: pointer;
+            }
+
+            .login-bnt2 {
+              width: 64px;
+              height: 24px;
+              border: 1px solid #e7000b;
+              color: #e7000b;
+              border-radius: 24px;
+              font-size: 12px;
+              margin-left: 10px;
+              cursor: pointer;
+            }
+          }
+        }
+
+        // .login-bos {
+        //   width: calc(100% - 20px);
+        //   height: 110px;
+        //   border-bottom: 1px solid #e5e7eb;
+        //   margin: 0 10px;
+        //   display: flex;
+        //   flex-direction: column;
+        //   justify-content: space-between;
+        //   padding: 16px 0;
+
+        //   .login-box {
+        //     display: flex;
+        //     align-items: center;
+
+        //     img {
+        //       width: 40px;
+        //       height: 40px;
+        //       margin-right: 8px;
+        //       border-radius: 40px;
+        //     }
+
+        //     .login-btn {
+        //       width: 100%;
+        //     }
+
+        //     .login1 {
+        //       font-size: 13px;
+        //       color: #444444;
+        //     }
+
+        //     .login2 {
+        //       margin-top: 2px;
+        //       font-size: 12px;
+        //       color: #6a7282;
+        //     }
+        //   }
+        // }
+
+        .order-bos {
+          width: calc(100% - 20px);
+          height: 110px;
+          font-size: 14px;
+          padding: 16px 0;
+          border-bottom: 1px solid #e5e7eb;
+          margin: 0 10px;
+          img {
+            width: 28px;
+            height: 28px;
+          }
+          .order-num {
+            color: #e7000b;
+            font-size: 14px;
+            margin-top: 2px;
+          }
         }
         }
 
 
         .real-time {
         .real-time {
@@ -517,7 +634,7 @@ getRecommendGiftFloorList({}).then((res) => {
 
 
           .real-list {
           .real-list {
             width: 100%;
             width: 100%;
-            font-size: 14px;
+            font-size: 12px;
             color: #1d2129;
             color: #1d2129;
             margin-bottom: 12px;
             margin-bottom: 12px;
             cursor: pointer;
             cursor: pointer;

+ 124 - 27
src/views/home/index-mro.vue

@@ -46,34 +46,46 @@
         </div>
         </div>
         <!-- 右边 -->
         <!-- 右边 -->
         <div class="head-right">
         <div class="head-right">
-          <div class="login-bos">
+          <div v-if="userInfo.userId" class="order-bos flex-column-between">
+            <div class="flex-row-start">
+              <img src="@/assets/images/logo2.png" alt="" />
+              <div class="ellipsis">{{ userInfo.nickName }}</div>
+            </div>
+            <div class="flex-row-start">
+              <div class="flex-1 flex-column-center">
+                <div>待付款</div>
+                <div class="order-num">{{ countData.pendingPaymentCount || 0 }}</div>
+              </div>
+              <div class="flex-1 flex-column-center">
+                <div>待发货</div>
+                <div class="order-num">{{ countData.pendingShipmentCount || 0 }}</div>
+              </div>
+              <div class="flex-1 flex-column-center">
+                <div>待收货</div>
+                <div class="order-num">{{ countData.pendingReceiptCount || 0 }}</div>
+              </div>
+            </div>
+          </div>
+          <div class="login-bos" v-else>
             <div class="login-box">
             <div class="login-box">
-              <img :src="userInfo.avatar ? userInfo.avatar : profile" alt="" />
+              <img src="@/assets/images/logo2.png" alt="" />
               <div>
               <div>
                 <div class="login1">您好,欢迎来到优易达</div>
                 <div class="login1">您好,欢迎来到优易达</div>
-                <div class="login2">{{ userInfo.nickName ? userInfo.nickName : '请先登录' }}</div>
+                <div class="login2">请先登录</div>
               </div>
               </div>
             </div>
             </div>
-            <div class="login-btn">
-              <el-button v-if="!userInfo.nickName" type="primary" round size="small" style="width: 64px" @click="onPath('/login')">登录</el-button>
-              <el-button v-if="!userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onPath('/reg')"
-                >注册</el-button
-              >
-              <el-button v-if="userInfo.nickName" type="primary" plain round size="small" style="width: 64px" @click="onPath('/reg')">退出</el-button>
+            <div class="loginBtn-bos flex-row-center">
+              <div @click="onPath('/login')" class="login-bnt1 flex-row-center">登录</div>
+              <div @click="onPath('/breg')" class="login-bnt2 flex-row-center">注册</div>
             </div>
             </div>
           </div>
           </div>
           <div class="real-time">
           <div class="real-time">
             <div class="real-title flex-row-between">
             <div class="real-title flex-row-between">
               <div class="real1">优易资讯</div>
               <div class="real1">优易资讯</div>
-              <div class="real2 flex-row-start">
-                <div>更多</div>
-                <el-icon :size="13" color="#83899F">
-                  <ArrowRight />
-                </el-icon>
-              </div>
+              <div class="real2 flex-row-start"></div>
             </div>
             </div>
             <template v-for="(item, index) in realList" :key="index">
             <template v-for="(item, index) in realList" :key="index">
-              <div class="real-list ellipsis" v-if="Number(index) < 7">{{ item.announcementTitle }}</div>
+              <div @click="onPath('/solve/real?id=' + item.id)" class="real-list ellipsis" v-if="Number(index) < 7">{{ item.announcementTitle }}</div>
             </template>
             </template>
           </div>
           </div>
           <div class="interests">
           <div class="interests">
@@ -191,7 +203,8 @@ import {
   getRecommendedCategory,
   getRecommendedCategory,
   getRecommendedCategoryProductList
   getRecommendedCategoryProductList
 } from '@/api/home/index-mro';
 } from '@/api/home/index-mro';
-import { getYouYiZiXunPage } from '@/api/home/index';
+import Cookies from 'js-cookie';
+import { getYouYiZiXunPage, countOrder } from '@/api/home/index';
 import { onPath } from '@/utils/siteConfig';
 import { onPath } from '@/utils/siteConfig';
 import { getToken } from '@/utils/auth';
 import { getToken } from '@/utils/auth';
 import { getInfo } from '@/api/login';
 import { getInfo } from '@/api/login';
@@ -212,12 +225,20 @@ const goodsList = ref<any>([]);
 const recommendNav = ref<any>([]);
 const recommendNav = ref<any>([]);
 const recommendList = ref<any>([]);
 const recommendList = ref<any>([]);
 const categoryId = ref<any>('');
 const categoryId = ref<any>('');
+const countData = ref<any>({});
 
 
 onMounted(() => {
 onMounted(() => {
-  if (getToken()) {
+  const token = Cookies.get('Authorization');
+  if (token) {
     getInfo().then((res) => {
     getInfo().then((res) => {
       if (res.code == 200) {
       if (res.code == 200) {
         userInfo.value = res.data.user;
         userInfo.value = res.data.user;
+
+        countOrder({}).then((res1) => {
+          if (res1.code == 200) {
+            countData.value = res1.data || {};
+          }
+        });
       }
       }
     });
     });
   }
   }
@@ -477,18 +498,17 @@ const onCarousel = (res: any) => {
 
 
       // 头部中间
       // 头部中间
       .carousel-bos {
       .carousel-bos {
-        width: 756px;
+        flex: 1;
         height: 540px;
         height: 540px;
         img {
         img {
-          width: 756px;
+          width: 100%;
           height: 540px;
           height: 540px;
         }
         }
       }
       }
 
 
       //右边
       //右边
       .head-right {
       .head-right {
-        flex: 1;
-        width: 0;
+        width: 230px;
         height: 540px;
         height: 540px;
         background: #ffffff;
         background: #ffffff;
         display: flex;
         display: flex;
@@ -515,10 +535,6 @@ const onCarousel = (res: any) => {
               border-radius: 40px;
               border-radius: 40px;
             }
             }
 
 
-            .login-btn {
-              width: 100%;
-            }
-
             .login1 {
             .login1 {
               font-size: 13px;
               font-size: 13px;
               color: #444444;
               color: #444444;
@@ -530,6 +546,87 @@ const onCarousel = (res: any) => {
               color: #6a7282;
               color: #6a7282;
             }
             }
           }
           }
+
+          .loginBtn-bos {
+            width: 100%;
+
+            .login-bnt1 {
+              width: 64px;
+              height: 24px;
+              background-color: #e7000b;
+              color: #ffffff;
+              border-radius: 24px;
+              font-size: 12px;
+              cursor: pointer;
+            }
+
+            .login-bnt2 {
+              width: 64px;
+              height: 24px;
+              border: 1px solid #e7000b;
+              color: #e7000b;
+              border-radius: 24px;
+              font-size: 12px;
+              margin-left: 10px;
+              cursor: pointer;
+            }
+          }
+        }
+
+        // .login-bos {
+        //   width: calc(100% - 20px);
+        //   height: 110px;
+        //   border-bottom: 1px solid #e5e7eb;
+        //   margin: 0 10px;
+        //   display: flex;
+        //   flex-direction: column;
+        //   justify-content: space-between;
+        //   padding: 16px 0;
+
+        //   .login-box {
+        //     display: flex;
+        //     align-items: center;
+
+        //     img {
+        //       width: 40px;
+        //       height: 40px;
+        //       margin-right: 8px;
+        //       border-radius: 40px;
+        //     }
+
+        //     .login-btn {
+        //       width: 100%;
+        //     }
+
+        //     .login1 {
+        //       font-size: 13px;
+        //       color: #444444;
+        //     }
+
+        //     .login2 {
+        //       margin-top: 2px;
+        //       font-size: 12px;
+        //       color: #6a7282;
+        //     }
+        //   }
+        // }
+
+        .order-bos {
+          width: calc(100% - 20px);
+          height: 110px;
+          font-size: 14px;
+          padding: 16px 0;
+          border-bottom: 1px solid #e5e7eb;
+          margin: 0 10px;
+          img {
+            width: 28px;
+            height: 28px;
+          }
+          .order-num {
+            color: #e7000b;
+            font-size: 14px;
+            margin-top: 2px;
+          }
         }
         }
 
 
         .real-time {
         .real-time {
@@ -569,7 +666,7 @@ const onCarousel = (res: any) => {
 
 
           .real-list {
           .real-list {
             width: 100%;
             width: 100%;
-            font-size: 14px;
+            font-size: 12px;
             color: #1d2129;
             color: #1d2129;
             margin-bottom: 12px;
             margin-bottom: 12px;
             cursor: pointer;
             cursor: pointer;

+ 4 - 4
src/views/home/index.vue

@@ -54,15 +54,15 @@
           <div class="flex-row-start">
           <div class="flex-row-start">
             <div class="flex-1 flex-column-center">
             <div class="flex-1 flex-column-center">
               <div>待付款</div>
               <div>待付款</div>
-              <div class="order-num">{{ countData.pendingPaymentCount }}</div>
+              <div class="order-num">{{ countData.pendingPaymentCount || 0 }}</div>
             </div>
             </div>
             <div class="flex-1 flex-column-center">
             <div class="flex-1 flex-column-center">
               <div>待发货</div>
               <div>待发货</div>
-              <div class="order-num">{{ countData.pendingShipmentCount }}</div>
+              <div class="order-num">{{ countData.pendingShipmentCount || 0}}</div>
             </div>
             </div>
             <div class="flex-1 flex-column-center">
             <div class="flex-1 flex-column-center">
               <div>待收货</div>
               <div>待收货</div>
-              <div class="order-num">{{ countData.pendingReceiptCount }}</div>
+              <div class="order-num">{{ countData.pendingReceiptCount || 0}}</div>
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>
@@ -420,7 +420,7 @@ onMounted(() => {
 
 
         countOrder({}).then((res1) => {
         countOrder({}).then((res1) => {
           if (res1.code == 200) {
           if (res1.code == 200) {
-            countData.value = res1.data;
+            countData.value = res1.data || {};
           }
           }
         });
         });
       }
       }

+ 153 - 0
src/views/home/pccomponents/index.ts

@@ -0,0 +1,153 @@
+import type { Component } from 'vue';
+import { markRaw } from 'vue';
+const createComponentMap = (name: string) => ({
+  pagePath: `./pages/${name}.vue`,
+  fid: 1
+});
+
+// 组件列表配置
+export const componentImportConfigs: any = [
+  {
+    name: '头部组件',
+    icon: 'iconfont iconfuwenbenpc',
+    id: 1,
+    enabled: true,
+    ...createComponentMap('head')
+  },
+  {
+    name: '文本标题',
+    icon: 'iconfont iconbiaotipc',
+    id: 2,
+    enabled: true,
+    ...createComponentMap('textTitle')
+  },
+  {
+    name: '图文导航',
+    icon: 'iconfont icontuwendaohangpc',
+    id: 3,
+    enabled: true,
+    ...createComponentMap('navigation')
+  },
+  {
+    name: '图片魔方',
+    icon: 'iconfont iconmofangpc',
+    id: 4,
+    enabled: true,
+    ...createComponentMap('imageCube')
+  },
+  // {
+  //   name: '活动魔方',
+  //   icon: 'iconfont iconmofangpc',
+  //   enabled: true,
+  //   id: 5
+  // },
+  {
+    name: '轮播图',
+    icon: 'iconfont icona-tupianzhanbopc302',
+    enabled: true,
+    id: 6,
+    ...createComponentMap('carousel')
+  },
+  {
+    name: '文章咨询',
+    icon: 'iconfont icongonggaopc',
+    enabled: true,
+    id: 7,
+    ...createComponentMap('article')
+  },
+  {
+    name: '品牌组件',
+    icon: 'iconfont iconmiaoshashangpin',
+    enabled: true,
+    id: 8,
+    ...createComponentMap('brand')
+  },
+  {
+    name: '图文广告',
+    icon: 'iconfont icontupiandaohangpc',
+    enabled: true,
+    id: 9,
+    ...createComponentMap('advert')
+  },
+  // {
+  //   name: '楼层组件',
+  //   icon: 'iconfont iconshangpinliebiaopc',
+  //   enabled: true,
+  //   id: 10,
+  //   ...createComponentMap('floor')
+  // },
+  // {
+  //   name: '商品组件',
+  //   icon: 'iconfont icona-shangpintuijianpc30',
+  //   enabled: true,
+  //   id: 11,
+  //   ...createComponentMap('goods')
+  // },
+  // {
+  //   name: '多商品组',
+  //   icon: 'iconfont iconduoshangpinzupc',
+  //   enabled: true,
+  //   id: 12,
+  //   ...createComponentMap('goodsList')
+  // },
+  // {
+  //   name: '发现组件',
+  //   icon: 'iconfont iconjifenshangpinpc',
+  //   enabled: true,
+  //   id: 13,
+  //   ...createComponentMap('discover')
+  // },
+  // {
+  //   name: '热区',
+  //   icon: 'iconfont iconrequpc',
+  //   enabled: true,
+  //   id: 14,
+  //   ...createComponentMap('hot')
+  // }
+];
+
+/**
+ * 加载所有组件
+ * @returns 组件配置列表
+ */
+export async function loadDiyComponents(): Promise<any[]> {
+  const components: any[] = [];
+
+  const loadPromises = componentImportConfigs
+    .filter((config: any) => config.enabled !== false)
+    .map(async (config: any) => {
+      try {
+        const [pageModule] = await Promise.all([import(/* @vite-ignore */ config.pagePath)]);
+        return {
+          name: config.name,
+          icon: config.icon,
+          fid: config.fid,
+          id: config.id,
+          components: markRaw(pageModule.default),
+          enabled: true
+        } as any;
+      } catch (error) {
+        console.warn(`加载组件失败:${config.name}`, error);
+        return null;
+      }
+    });
+
+  const results = await Promise.all(loadPromises);
+  return results.filter((item): item is any => item !== null);
+}
+
+/**
+ * 获取组件分组配置
+ * @param components 组件列表
+ * @returns 分组后的组件配置
+ */
+export function getComponentGroups(components: any[]): any[] {
+  return [
+    {
+      name: '基础组件',
+      list: components,
+      id: 1
+    }
+    // 后续可扩展多个分组,如:营销组件、商品组件等
+  ];
+}

+ 174 - 0
src/views/home/pccomponents/pages/activity.vue

@@ -0,0 +1,174 @@
+<template>
+  <div class="pcPages">
+    <div class="carousel-bos" :style="warpCss" v-if="componentData.styleType == 3">
+      <el-carousel :height="270 * componentData.count + (componentData.count == 2 ? 10 : 0) + 'px'" :autoplay="false" arrow="always">
+        <el-carousel-item v-for="(item1, index1) in dataList" :key="index1" class="w100% h100%">
+          <div class="carousel-list">
+            <div v-for="(item, index) in item1" :key="index" class="data-list flex-column-between" :style="boxCss">
+              <el-image
+                class="img"
+                :src="item.imageUrl ? item.imageUrl : figure"
+                :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+                :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+              />
+              <div :style="titleCss" class="title">{{ item.title || '' }}</div>
+              <div :style="subtitleCss" class="mt-[2px] mb-[12px] subtitle ellipsis">{{ item.subtitle || '' }}</div>
+            </div>
+          </div>
+        </el-carousel-item>
+      </el-carousel>
+    </div>
+    <div v-else :style="warpCss" class="data-bos">
+      <div v-for="(item, index) in componentData.navlList" :key="index" class="data-list flex-column-between" :style="boxCss">
+        <el-image
+          class="img"
+          :src="item.imageUrl ? item.imageUrl : figure"
+          :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+          :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+        />
+        <div :style="titleCss" class="title">{{ item.title || '' }}</div>
+        <div :style="subtitleCss" class="mt-[2px] mb-[12px] subtitle ellipsis">{{ item.subtitle || '' }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import usePcdiyStore from '@/store/modules/pcdiy';
+import figure from '@/assets/images/figure.png';
+const diyStore = usePcdiyStore();
+const props = defineProps<{
+    index: number; // 确保声明 index 为可选属性
+    row?: any;
+}>();
+const componentData = props.row ? props.row : diyStore.componentList[props.index];
+
+const dataList = computed(() => {
+  const chunkSize = componentData.number * componentData.count;
+  const result = [];
+  for (let i = 0; i < componentData.navlList.length; i += chunkSize) {
+    const chunk = componentData.navlList.slice(i, i + chunkSize);
+    result.push(chunk);
+  }
+  return result;
+});
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+    if (componentData.styleType == 1) style += 'flex-wrap:wrap' + ';';
+  }
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+  return style;
+});
+
+// 标题样式
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
+  if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
+  if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
+  return style;
+});
+
+// 副标题样式
+const subtitleCss = computed(() => {
+  let style = '';
+  if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
+  if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .data-bos {
+    display: flex;
+    gap: 10px;
+    width: 100%;
+    overflow-x: auto;
+    .data-list {
+      min-height: 270px;
+      width: 0;
+
+      .title {
+        text-align: center;
+        padding: 0 15px;
+      }
+
+      .subtitle {
+        text-align: center;
+        padding: 0 15px;
+      }
+
+      .img {
+        height: 200px;
+        width: 100%;
+      }
+    }
+  }
+
+  .carousel-bos {
+    .carousel-list {
+      width: 100%;
+      height: 100%;
+      display: flex;
+      gap: 10px;
+      flex-wrap: wrap;
+      .data-list {
+        height: 270px;
+        width: 0;
+
+        .title {
+          text-align: center;
+          padding: 0 15px;
+        }
+
+        .subtitle {
+          text-align: center;
+          padding: 0 15px;
+        }
+
+        .img {
+          height: 200px;
+          width: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 181 - 0
src/views/home/pccomponents/pages/advert.vue

@@ -0,0 +1,181 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="carousel-bos" v-if="componentData.styleType == 3">
+      <el-carousel :height="270 * componentData.count + (componentData.count == 2 ? 10 : 0) + 'px'" :autoplay="false" arrow="always">
+        <el-carousel-item v-for="(item1, index1) in dataList" :key="index1" class="w100% h100%">
+          <div class="carousel-list">
+            <div v-for="(item, index) in item1" :key="index" class="data-list hover-color flex-column-between" :style="boxCss">
+              <el-image
+                class="img"
+                :src="item.imageUrl ? item.imageUrl : figure"
+                :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+                :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+              />
+              <div :style="titleCss" class="title zi-hover">{{ item.title || '' }}</div>
+              <div :style="subtitleCss" class="mt-[2px] mb-[12px] subtitle ellipsis">{{ item.subtitle || '' }}</div>
+            </div>
+          </div>
+        </el-carousel-item>
+      </el-carousel>
+    </div>
+    <div v-else class="data-bos">
+      <div v-for="(item, index) in componentData.navlList" :key="index" class="data-list hover-color flex-column-between" :style="boxCss">
+        <el-image
+          class="img"
+          :src="item.imageUrl ? item.imageUrl : figure"
+          :fit="item.imageUrl ? (item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover') : 'cover'"
+          :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+        />
+        <div :style="titleCss" class="title zi-hover">{{ item.title || '' }}</div>
+        <div :style="subtitleCss" class="mt-[2px] mb-[12px] subtitle ellipsis">{{ item.subtitle || '' }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import figure from '@/assets/images/figure.png';
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+
+const dataList = computed(() => {
+  const chunkSize = componentData.number * componentData.count;
+  const result = [];
+  for (let i = 0; i < componentData.navlList.length; i += chunkSize) {
+    const chunk = componentData.navlList.slice(i, i + chunkSize);
+    result.push(chunk);
+  }
+  return result;
+});
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+    if (componentData.styleType == 1) style += 'flex-wrap:wrap' + ';';
+  }
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+  return style;
+});
+
+// 标题样式
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
+  if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
+  if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
+  return style;
+});
+
+// 副标题样式
+const subtitleCss = computed(() => {
+  let style = '';
+  if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
+  if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .data-bos {
+    display: flex;
+    gap: 10px;
+    width: 100%;
+    overflow-x: auto;
+    .data-list {
+      min-height: 270px;
+      width: 0;
+
+      .title {
+        text-align: center;
+        padding: 0 15px;
+      }
+
+      .subtitle {
+        text-align: center;
+        padding: 0 15px;
+      }
+
+      .img {
+        height: 200px;
+        width: 100%;
+      }
+    }
+  }
+
+  .carousel-bos {
+    .carousel-list {
+      width: 100%;
+      height: 100%;
+      display: flex;
+      gap: 10px;
+      flex-wrap: wrap;
+      .data-list {
+        height: 270px;
+        width: 0;
+
+        .title {
+          text-align: center;
+          padding: 0 15px;
+        }
+
+        .subtitle {
+          text-align: center;
+          padding: 0 15px;
+        }
+
+        .img {
+          height: 200px;
+          width: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 194 - 0
src/views/home/pccomponents/pages/article.vue

@@ -0,0 +1,194 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="article-bos" :style="boxCss">
+      <template v-for="(item, index) in dataList" :key="index">
+        <div
+          class="article-list hover-color"
+          :style="dataCss"
+          v-if="componentData.dataType == 2 && componentData.dataIds.length > 0 ? true : index < componentData.dataNumber"
+        >
+          <img :src="item.caseImage ? item.caseImage : figure" alt="" />
+          <div class="caseTitle zi-hover">{{ item.caseTitle }}</div>
+          <div class="projectBrief">{{ item.projectBrief }}</div>
+        </div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { getServiceCaseList } from '@/api/home/diy';
+import figure from '@/assets/images/figure.png';
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+const dataList = ref<any>([]);
+
+onMounted(() => {
+  getDataList();
+});
+const getDataList = () => {
+  // 默认
+  if (componentData.dataType == 1) {
+    getServiceCaseList({ pageSize: 20 }).then((res) => {
+      if (res.code == 200) {
+        dataList.value = res.rows;
+      }
+    });
+  } else {
+    //手动选择
+    if (componentData.dataIds.length > 0) {
+      getServiceCaseList({ pageNum: 1, pageSize: 20, ids: componentData.dataIds.join(',') }).then((res) => {
+        if (res.code == 200) {
+          dataList.value = res.rows;
+        }
+      });
+    }
+  }
+};
+
+// 监听 componentData 变化,重新请求数据
+watch(
+  () => componentData.dataType,
+  () => {
+    getDataList();
+  }
+);
+
+watch(
+  () => componentData.dataIds,
+  () => {
+    getDataList();
+  },
+  { deep: true } // 5. 数组变化需要 deep 监听
+);
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  return style;
+});
+
+//样式
+const dataCss = computed(() => {
+  let style = '';
+  //背景颜色
+  if (componentData.backgroundColor) style += 'background-color:' + componentData.backgroundColor + ';';
+  //圆角
+  if (componentData.boxTopRounded) style += 'border-top-left-radius:' + componentData.boxTopRounded + 'px;';
+  if (componentData.boxTopRounded) style += 'border-top-right-radius:' + componentData.boxTopRounded + 'px;';
+  if (componentData.boxBottomRounded) style += 'border-bottom-left-radius:' + componentData.boxBottomRounded + 'px;';
+  if (componentData.boxBottomRounded) style += 'border-bottom-right-radius:' + componentData.boxBottomRounded + 'px;';
+  //投影
+  if (componentData.border == 2 && componentData.borderColor) style += 'box-shadow:' + componentData.borderColor + ' 0px 0px 5px';
+  //描边
+  if (componentData.border == 3 && componentData.borderColor) style += 'border:' + componentData.borderColor + ' 1px solid;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+
+  .article-bos {
+    width: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+
+    .article-list {
+      flex: 0 0 calc((100% - 45px) / 4);
+      width: 0;
+      overflow: hidden;
+      cursor: pointer;
+
+      .caseTitle {
+        font-size: 14px;
+        color: #333333;
+        height: 20px;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        width: 100%;
+        margin: 5px 0;
+        padding: 0 15px;
+      }
+
+      .projectBrief {
+        font-size: 12px;
+        color: #666666;
+        height: 50px;
+        display: -webkit-box;
+        -webkit-line-clamp: 3;
+        line-clamp: 3;
+        /* 添加标准属性 */
+        -webkit-box-orient: vertical;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        width: 100%;
+        padding: 0 15px;
+        margin-bottom: 15px;
+      }
+
+      img {
+        width: 100%;
+        height: 165px;
+      }
+
+      // flex: 0 0 calc((100% - ${(componentData.number - 1) * 10}px);
+    }
+  }
+}
+</style>

+ 179 - 0
src/views/home/pccomponents/pages/brand.vue

@@ -0,0 +1,179 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="big-brand" :style="boxCss">
+      <el-image
+        class="bigBrand-one"
+        :src="componentData.imageUrl ? componentData.imageUrl : figure"
+        :fit="componentData.imageUrl ? (componentData.imgType == 1 ? 'fill' : componentData.imgType == 2 ? 'contain' : 'cover') : 'cover'"
+        :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}"
+      />
+      <div class="bigBrand-bos">
+        <template v-for="(item, index) in componentData.brandList" :key="index">
+          <div
+            class="bigBrand-list hover-color"
+            v-if="Number(index) < 10"
+            :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}"
+          >
+            <el-image
+              class="img"
+              :src="item.imageUrl ? item.imageUrl : brand1"
+              :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+              :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+            />
+            <div :style="titleCss" class="bigBrand1 zi-hover">{{ item.title || '' }}</div>
+            <div :style="subtitleCss" class="bigBrand2">
+              {{ item.subtitle || '' }}
+            </div>
+          </div>
+        </template>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import figure from '@/assets/images/figure.png';
+import brand1 from '@/assets/images/pcdiy/brand1.png';
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
+  return style;
+});
+
+// 标题样式
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
+  if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
+  if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
+  return style;
+});
+
+// 副标题样式
+const subtitleCss = computed(() => {
+  let style = '';
+  if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
+  if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  // 大牌推荐
+  .big-brand {
+    height: 340px;
+    display: flex;
+    gap: 10px;
+    width: 100%;
+
+    .bigBrand-one {
+      width: 230px;
+      height: 340px;
+    }
+
+    .bigBrand-bos {
+      flex: 1;
+      display: flex;
+      flex-wrap: wrap;
+      gap: 10px;
+      overflow: hidden;
+      height: 340px;
+
+      .bigBrand-list {
+        flex: 0 0 calc((100% - 40px) / 5);
+        height: 165px;
+        background: #ffffff;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        padding: 20px 20px 0 20px;
+        width: 0;
+
+        .img {
+          width: 120px;
+          height: 50px;
+        }
+
+        .bigBrand1 {
+          font-weight: 600;
+          font-size: 14px;
+          color: #101828;
+          margin: 5px 0 4px 0;
+        }
+
+        .bigBrand2 {
+          font-weight: 400;
+          font-size: 12px;
+          color: #364153;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          line-clamp: 2;
+          -webkit-box-orient: vertical;
+          overflow: hidden;
+          text-overflow: ellipsis;
+          text-align: left;
+          width: 100%;
+        }
+      }
+    }
+  }
+}
+</style>

+ 121 - 0
src/views/home/pccomponents/pages/carousel.vue

@@ -0,0 +1,121 @@
+<template>
+  <div class="pcPages" :style="warpCss" :class="['position' + componentData.position, 'styleType' + componentData.styleType]">
+    <el-carousel arrow="always" :interval="componentData.interval" :height="componentData.imageHeight + 'px'" class="carousel-bos" :style="boxCss">
+      <el-carousel-item v-for="(item, index) in componentData.imagelList" :key="index" class="carousel-item">
+        <el-image
+          class="img"
+          :src="item.imageUrl ? item.imageUrl : figure"
+          :fit="item.imageUrl ? (item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover') : 'cover'"
+        />
+      </el-carousel-item>
+    </el-carousel>
+  </div>
+</template>
+
+<script lang="ts" setup>
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+document.documentElement.style.setProperty('--carousel-color2', componentData.carouselStyleColor ? componentData.carouselStyleColor : '#ffffff');
+import figure from '@/assets/images/figure.png';
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  //圆角
+  if (componentData.imageRadius) style += 'border-radius:' + componentData.imageRadius + 'px;';
+  return style;
+});
+
+watch(
+  () => componentData.carouselStyleColor,
+  () => {
+    document.documentElement.style.setProperty('--carousel-color2', componentData.carouselStyleColor ? componentData.carouselStyleColor : '#ffffff');
+  }
+);
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+
+  .carousel-bos {
+    width: 100%;
+    overflow: hidden;
+
+    .carousel-item {
+      width: 100%;
+      height: 100%;
+
+      .img {
+        width: 100%;
+        height: 100%;
+        cursor: pointer;
+      }
+    }
+  }
+
+  &.position1 {
+    :deep(.el-carousel__indicators--horizontal) {
+      left: 5%;
+    }
+  }
+  &.position2 {
+    :deep(.el-carousel__indicators--horizontal) {
+      left: 50%;
+    }
+  }
+  &.position3 {
+    :deep(.el-carousel__indicators--horizontal) {
+      left: 95%;
+    }
+  }
+  &.styleType2 {
+    :deep(.el-carousel__button) {
+      height: 10px;
+      width: 10px;
+      border-radius: 10px;
+    }
+  }
+  :deep(.el-carousel__button) {
+    background-color: var(--carousel-color2);
+  }
+}
+</style>

+ 450 - 0
src/views/home/pccomponents/pages/discover.vue

@@ -0,0 +1,450 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="discover-bos" :style="boxCss">
+      <!-- 头部 -->
+      <div class="home-title flex-row-between" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+        <div>
+          <span :style="titleCss" class="title1 mr-[10px]">{{ componentData.title }}</span>
+          <span :style="subtitleCss">{{ componentData.subtitle }}</span>
+        </div>
+        <div class="title-more flex-row-start">
+          <div class="ml-[10px]" v-for="(item, index) in componentData.labelList" :key="index">{{ item.title }}</div>
+        </div>
+      </div>
+      <!-- 中间区域 -->
+      <div class="discover-box">
+        <el-image
+          class="discover-image"
+          :src="componentData.imageUrl ? componentData.imageUrl : figure"
+          :fit="componentData.imgType == 1 ? 'fill' : componentData.imgType == 2 ? 'contain' : 'cover'"
+          :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}"
+        />
+        <div class="plan-bos" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+          <div class="plan-head">方案推荐</div>
+          <div v-for="(item, index) in componentData.planList" :key="index" class="plan-list">
+            <el-image
+              class="plan-image"
+              :src="item.imageUrl ? item.imageUrl : figure"
+              :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+              :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+            />
+            <div class="plan-box flex-column-between">
+              <div class="plan-title ellipsis">{{ item.title }}</div>
+              <div class="plan-subtitle">{{ item.subtitle }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="detect-bos" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+          <div class="detect-head">发现</div>
+          <div class="detect-box">
+            <div class="detect-two">
+              <div class="detect-list" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+                <div class="detect-item">
+                  <div class="detect-title ellipsis">{{ componentData.detectList[0].title }}</div>
+                  <div class="detect-subtitle mt-[6px] h-[32px]">{{ componentData.detectList[0].subtitle }}</div>
+                  <div class="detect-btn" :style="{ backgroundColor: componentData.boxColor }">立即进入</div>
+                </div>
+                <el-image
+                  class="detect-image"
+                  :src="componentData.detectList[0].imageUrl ? componentData.detectList[0].imageUrl : figure"
+                  :fit="componentData.detectList[0].imgType == 1 ? 'fill' : componentData.detectList[0].imgType == 2 ? 'contain' : 'cover'"
+                  :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+                />
+              </div>
+              <div class="detect-list" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+                <div class="detect-item">
+                  <div class="detect-title ellipsis">{{ componentData.detectList[1].title }}</div>
+                  <div class="detect-subtitle mt-[6px] h-[32px]">{{ componentData.detectList[1].subtitle }}</div>
+                  <div class="detect-btn" :style="{ backgroundColor: componentData.boxColor }">立即进入</div>
+                </div>
+                <el-image
+                  class="detect-image"
+                  :src="componentData.detectList[1].imageUrl ? componentData.detectList[1].imageUrl : figure"
+                  :fit="componentData.detectList[1].imgType == 1 ? 'fill' : componentData.detectList[1].imgType == 2 ? 'contain' : 'cover'"
+                  :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+                />
+              </div>
+            </div>
+            <div class="detect-one flex-column-between" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+              <div>
+                <div class="detect-title ellipsis">{{ componentData.detectList[2].title }}</div>
+                <div class="detect-subtitle mt-[6px]">{{ componentData.detectList[2].subtitle }}</div>
+              </div>
+              <el-image
+                class="detect-img"
+                :src="componentData.detectList[2].imageUrl ? componentData.detectList[2].imageUrl : figure"
+                :fit="componentData.detectList[2].imgType == 1 ? 'fill' : componentData.detectList[2].imgType == 2 ? 'contain' : 'cover'"
+                :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 底部 -->
+      <div class="discover-foot">
+        <div class="discover-tab" :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}">
+          <div class="tab-head" :style="{ color: componentData.boxColor }">采购导航</div>
+          <div class="tab-bos">
+            <div v-for="(item, index) in componentData.tabList" :key="index" class="tab-list flex-row-center">
+              {{ item.title }}
+            </div>
+          </div>
+        </div>
+        <div
+          class="goods-bos flex-column-between"
+          v-for="(item, index) in dataList"
+          :key="index"
+          :style="componentData.boxRadius ? { borderRadius: componentData.boxRadius + 'px' } : {}"
+        >
+          <img
+            class="goods-img"
+            :src="item.productImage ? item.productImage : figure"
+            alt=""
+            :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+          />
+          <div>
+            <div class="goods-name">{{ item.itemName || '' }}</div>
+            <div class="goods-price" :style="{ color: componentData.boxColor }">¥{{ item.memberPrice }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import figure from '@/assets/images/figure.png';
+import usePcdiyStore from '@/store/modules/pcdiy';
+import { listBase } from '@/api/pmsProduct/base';
+const diyStore = usePcdiyStore();
+
+const props = defineProps<{
+    index: number; // 确保声明 index 为可选属性
+  row?: any;
+}>();
+const componentData = props.row ? props.row : diyStore.componentList[props.index];
+const dataList = ref<any>([{}, {}, {}, {}]);
+
+onMounted(() => {
+  getDataList();
+});
+
+const getDataList = () => {
+  dataList.value = [{}, {}, {}, {}];
+  if (componentData.goodsIds.length > 0) {
+    listBase({ pageNum: 1, pageSize: 10, ids: componentData.goodsIds.join(',') }).then((res) => {
+      if (res.code == 200) {
+        dataList.value = res.rows;
+      }
+    });
+  }
+};
+
+watch(
+  () => componentData.goodsIds,
+  () => {
+    getDataList();
+  },
+  { deep: true } // 5. 数组变化需要 deep 监听
+);
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
+  return style;
+});
+
+// 标题样式
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
+  if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
+  if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
+  return style;
+});
+
+// 副标题样式
+const subtitleCss = computed(() => {
+  let style = '';
+  if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
+  if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .discover-bos {
+    width: 100%;
+    .home-title {
+      width: 100%;
+      background-color: #ffffff;
+      padding: 15px 20px;
+      .title-more {
+        font-size: 14px;
+        color: #333333;
+      }
+    }
+  }
+  //中间区域
+  .discover-box {
+    height: 340px;
+    width: 100%;
+    margin-top: 15px;
+    display: flex;
+    gap: 10px;
+
+    .discover-image {
+      width: 230px;
+      height: 340px;
+    }
+
+    // 方案
+    .plan-bos {
+      flex: 1;
+      height: 340px;
+      background: #ffffff;
+      padding: 0px 15px;
+      display: flex;
+      flex-direction: column;
+      min-width: 0;
+
+      .plan-head {
+        font-weight: 600;
+        font-size: 16px;
+        color: #101828;
+        height: 50px;
+        line-height: 50px;
+      }
+
+      .plan-list {
+        flex: 1;
+        display: flex;
+        border-bottom: 1px solid #e5e7eb;
+        cursor: pointer;
+        width: 100%;
+        margin-bottom: 14px;
+
+        &:last-child {
+          border-bottom: none;
+          margin-bottom: 0;
+        }
+
+        .plan-image {
+          width: 72px;
+          height: 72px;
+          margin-right: 10px;
+        }
+
+        .plan-box {
+          height: 72px;
+          flex: 1;
+          padding: 8px 0px 8px 5px;
+          width: 0;
+          .plan-title {
+            font-weight: 600;
+            font-size: 14px;
+            color: #101828;
+          }
+          .plan-subtitle {
+            height: 34px;
+            font-weight: 400;
+            font-size: 12px;
+            color: #364153;
+            display: -webkit-box;
+            -webkit-line-clamp: 2;
+            line-clamp: 2;
+            /* 添加标准属性 */
+            -webkit-box-orient: vertical;
+            overflow: hidden;
+            text-overflow: ellipsis;
+          }
+        }
+      }
+    }
+
+    .detect-bos {
+      width: 470px;
+      height: 340px;
+      background: #ffffff;
+      padding: 0px 15px 15px 15px;
+      .detect-head {
+        font-weight: 600;
+        font-size: 16px;
+        color: #101828;
+        height: 50px;
+        line-height: 50px;
+      }
+
+      .detect-box {
+        display: flex;
+        gap: 10px;
+        .detect-title {
+          font-weight: 600;
+          font-size: 14px;
+          color: #101828;
+        }
+        .detect-subtitle {
+          font-weight: 400;
+          font-size: 12px;
+          color: #364153;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          line-clamp: 2;
+          /* 添加标准属性 */
+          -webkit-box-orient: vertical;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+        .detect-two {
+          flex: 1;
+          width: 0;
+          .detect-list {
+            width: 100%;
+            height: 132.5px;
+            border: 1px solid #e5e7eb;
+            margin-top: 10px;
+            padding: 25px 10px;
+            display: flex;
+            gap: 10px;
+            &:first-child {
+              margin-top: 0;
+            }
+            .detect-item {
+              flex: 1;
+              width: 0;
+              .detect-btn {
+                width: 68px;
+                height: 24px;
+                text-align: center;
+                line-height: 24px;
+                font-size: 12px;
+                color: #ffffff;
+                margin-top: 12px;
+              }
+            }
+            .detect-image {
+              height: 72px;
+              width: 72px;
+            }
+          }
+        }
+        .detect-one {
+          width: 180px;
+          height: 275px;
+          border: 1px solid #e5e7eb;
+          background-color: #ffffff;
+          padding: 25px 10px;
+          .detect-img {
+            height: 124px;
+            width: 124px;
+            margin: 0 auto;
+          }
+        }
+      }
+    }
+  }
+  //底部
+  .discover-foot {
+    display: flex;
+    gap: 10px;
+    margin-top: 15px;
+    .discover-tab {
+      width: 230px;
+      height: 310px;
+      background: #ffffff;
+      padding: 0 15px 15px 15px;
+      .tab-head {
+        font-weight: 600;
+        font-size: 16px;
+        height: 50px;
+        line-height: 50px;
+      }
+      .tab-bos {
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        gap: 10px 0;
+        .tab-list {
+          width: 94px;
+          height: 32px;
+          background: #f4f4f4;
+          font-size: 14px;
+          color: #101828;
+          border-radius: 4px 4px 4px 4px;
+        }
+      }
+    }
+    .goods-bos {
+      flex: 0 0 calc((100% - 270px) / 4);
+      width: 0;
+      background: #ffffff;
+      height: 310px;
+      padding: 15px 20px;
+      .goods-img {
+        width: 100%;
+        height: 190px;
+      }
+      .goods-name {
+        width: 100%;
+        display: -webkit-box;
+        -webkit-line-clamp: 3;
+        line-clamp: 3;
+        /* 添加标准属性 */
+        -webkit-box-orient: vertical;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        font-size: 14px;
+        color: #101828;
+        height: 57px;
+      }
+      .goods-price {
+        font-size: 16px;
+        margin-top: 5px;
+      }
+    }
+  }
+}
+</style>

+ 253 - 0
src/views/home/pccomponents/pages/floor.vue

@@ -0,0 +1,253 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="floor-bos" :style="boxCss">
+      <el-image
+        class="floor-one"
+        :src="componentData.imageUrl ? componentData.imageUrl : figure"
+        :fit="componentData.imgType == 1 ? 'fill' : componentData.imgType == 2 ? 'contain' : 'cover'"
+        :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+      />
+      <div class="floor-box">
+        <div v-for="(item, index) in dataList" :key="index" class="goods-list flex-column-between">
+          <img
+            class="goods-img"
+            :src="item.productImage ? item.productImage : figure"
+            alt=""
+            :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+          />
+          <div v-if="componentData.goodsShow.includes(1)" class="itemName">{{ item.itemName || '' }}</div>
+          <div class="flex-row-between">
+            <div>
+              <span v-if="componentData.goodsShow.includes(2)" class="memberPrice" :style="{ color: componentData.btnbackgroundColor }"
+                >¥{{ item.memberPrice }}</span
+              >
+              <span v-if="componentData.goodsShow.includes(3)" class="marketPrice">¥{{ item.marketPrice }}</span>
+            </div>
+            <template v-if="componentData.btnShow">
+              <div v-if="componentData.btnStyle == 1" :style="btnCss1" class="btn1 ellipsis">{{ componentData.btnText }}</div>
+              <div v-if="componentData.btnStyle == 2" :style="btnCss2" class="btn2 flex-row-center">
+                <el-icon size="14"><Plus /></el-icon>
+              </div>
+              <div v-if="componentData.btnStyle == 3" :style="btnCss2" class="btn2 flex-row-center">
+                <icon name="iconfont icongouwuche" size="14px" />
+              </div>
+            </template>
+          </div>
+        </div>
+      </div>
+      <div class="goods-brand flex-column-between" v-if="componentData.styleType == 2">
+        <div class="brand-bos">
+          <template v-for="(item, index) in componentData.brandList" :key="index">
+            <el-image
+              v-if="Number(index) < 6"
+              class="brand-img"
+              :src="item.imageUrl ? item.imageUrl : figure"
+              :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+            />
+          </template>
+        </div>
+        <div class="brand-more flex-row-center" v-if="componentData.moreShow" :style="{ color: componentData.moreColor }">
+          <div>{{ componentData.moreTitle }}</div>
+          <el-icon><ArrowRight /></el-icon>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import figure from '@/assets/images/figure.png';
+import usePcdiyStore from '@/store/modules/pcdiy';
+import { listBase } from '@/api/pmsProduct/base';
+const diyStore = usePcdiyStore();
+
+const props = defineProps<{
+    index: number; // 确保声明 index 为可选属性
+  row?: any;
+}>();
+const componentData = props.row ? props.row : diyStore.componentList[props.index];
+const dataList = ref<any>([{}, {}, {}, {}, {}, {}, {}, {}]);
+
+onMounted(() => {
+  getDataList();
+});
+
+watch(
+  () => componentData.goodsIds,
+  () => {
+    getDataList();
+  },
+  { deep: true } // 5. 数组变化需要 deep 监听
+);
+
+const getDataList = () => {
+  dataList.value = [{}, {}, {}, {}, {}, {}, {}, {}];
+  //手动选择
+  if (componentData.goodsIds.length > 0) {
+    listBase({ pageNum: 1, pageSize: 20, ids: componentData.goodsIds.join(',') }).then((res) => {
+      if (res.code == 200) {
+        dataList.value = res.rows;
+      }
+    });
+  }
+};
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
+  return style;
+});
+
+const btnCss1 = computed(() => {
+  let style = '';
+  if (componentData.btnbackgroundColor) style += 'background-color:' + componentData.btnbackgroundColor + ';';
+  if (componentData.btnColor) style += 'color:' + componentData.btnColor + ';';
+  return style;
+});
+
+const btnCss2 = computed(() => {
+  let style = '';
+  if (componentData.btnbackgroundColor) style += 'color:' + componentData.btnbackgroundColor + ';';
+  if (componentData.btnbackgroundColor) style += 'border-color:' + componentData.btnbackgroundColor + ';';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .floor-bos {
+    height: 560px;
+    display: flex;
+    gap: 10px;
+    width: 100%;
+    .floor-one {
+      width: 230px;
+      height: 560px;
+    }
+    .floor-box {
+      flex: 1;
+      display: flex;
+      flex-wrap: wrap;
+      gap: 10px;
+      overflow: hidden;
+      .goods-list {
+        padding: 15px 10px;
+        height: 275px;
+        width: 0;
+        flex: 0 0 calc((100% - 30px) / 4);
+        background-color: #ffffff;
+        overflow: hidden;
+        border-radius: 10px;
+        .goods-img {
+          width: 100%;
+          height: 140px;
+        }
+        .itemName {
+          width: 100%;
+          font-size: 14px;
+          color: #101828;
+          display: -webkit-box;
+          -webkit-line-clamp: 2;
+          line-clamp: 2;
+          /* 添加标准属性 */
+          -webkit-box-orient: vertical;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+        .memberPrice {
+          font-size: 16px;
+          font-weight: bold;
+        }
+        .marketPrice {
+          font-size: 12px;
+          color: #99a1af;
+          line-height: 20px;
+          text-decoration-line: line-through;
+          text-transform: none;
+          margin-left: 6px;
+          color: #99a1af;
+        }
+
+        .btn1 {
+          padding: 5px 15px;
+          font-size: 12px;
+          border-radius: 15px;
+        }
+        .btn2 {
+          color: var(--el-color-primary);
+          border: 1px solid var(--el-color-primary);
+          height: 26px;
+          width: 26px;
+          border-radius: 50%;
+        }
+      }
+    }
+    .goods-brand {
+      width: 140px;
+      height: 560px;
+      border-radius: 10px;
+      background: #ffffff;
+      padding: 15px 10px;
+      .brand-bos {
+        width: 100%;
+        display: flex;
+        flex-direction: column;
+        gap: 10px 0;
+        .brand-img {
+          width: 100%;
+          height: 74px;
+          border-radius: 4px;
+          border: 1px solid #e5e7eb;
+          cursor: pointer;
+        }
+      }
+      .brand-more {
+        color: var(--el-color-primary);
+        font-size: 14px;
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>

+ 269 - 0
src/views/home/pccomponents/pages/goods.vue

@@ -0,0 +1,269 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="goods-bos" :style="boxCss">
+      <div v-for="(item, index) in dataList" :key="index" class="goods-list flex-column-between" :style="goodsCss">
+        <img
+          class="goods-img"
+          :src="item.productImage ? item.productImage : figure"
+          alt=""
+          :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+        />
+        <div v-if="componentData.goodsShow.includes(1)" :style="titleCss" class="itemName">{{ item.itemName || '' }}</div>
+        <div class="flex-row-between">
+          <div>
+            <span v-if="componentData.goodsShow.includes(2)" class="memberPrice" :style="{ color: componentData.priceColor }"
+              >¥{{ item.memberPrice }}</span
+            >
+            <span v-if="componentData.goodsShow.includes(3)" class="marketPrice">¥{{ item.marketPrice }}</span>
+          </div>
+          <template v-if="componentData.btnShow">
+            <div v-if="componentData.btnStyle == 1" :style="btnCss1" class="btn1">{{ componentData.btnText }}</div>
+            <div v-if="componentData.btnStyle == 2" :style="btnCss2" class="btn2 flex-row-center">
+              <el-icon size="14"><Plus /></el-icon>
+            </div>
+            <div v-if="componentData.btnStyle == 3" :style="btnCss2" class="btn2 flex-row-center">
+              <icon name="iconfont icongouwuche" size="14px" />
+            </div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import figure from '@/assets/images/figure.png';
+import usePcdiyStore from '@/store/modules/pcdiy';
+import { listBase } from '@/api/pmsProduct/base';
+const diyStore = usePcdiyStore();
+
+const props = defineProps<{
+   index: number; // 确保声明 index 为可选属性
+  row?: any;
+}>();
+const componentData = props.row ? props.row : diyStore.componentList[props.index];
+const dataList = ref<any>([{}, {}, {}, {}, {}]);
+
+onMounted(() => {
+  getDataList();
+});
+
+const getDataList = () => {
+  dataList.value = [{}, {}, {}, {}, {}];
+  //手动选择
+  if (componentData.goodsType == 1) {
+    if (componentData.goodsIds.length > 0) {
+      listBase({ pageNum: 1, pageSize: 20, ids: componentData.goodsIds.join(',') }).then((res) => {
+        if (res.code == 200) {
+          dataList.value = res.rows;
+        }
+      });
+    }
+  } else if (componentData.goodsType == 2) {
+    //分类查询
+    if (componentData.goodsClassify) {
+      listBase({
+        pageNum: 1,
+        pageSize: componentData.goodsNumber == 0 ? 50 : componentData.goodsNumber,
+        topCategoryId: componentData.topCategoryId,
+        mediumCategoryId: componentData.mediumCategoryId,
+        bottomCategoryId: componentData.bottomCategoryId
+      }).then((res) => {
+        if (res.code == 200) {
+          dataList.value = res.rows;
+        }
+      });
+    }
+  } else if (componentData.goodsType == 3) {
+    //品牌查询
+    if (componentData.goodsBrand) {
+      listBase({
+        pageNum: 1,
+        pageSize: componentData.goodsNumber == 0 ? 50 : componentData.goodsNumber,
+        brandId: componentData.goodsBrand
+      }).then((res) => {
+        if (res.code == 200) {
+          dataList.value = res.rows;
+        }
+      });
+    }
+  }
+};
+
+watch(
+  () => componentData.goodsType,
+  () => {
+    getDataList();
+  }
+);
+
+watch(
+  () => componentData.goodsClassify,
+  () => {
+    getDataList();
+  }
+);
+
+watch(
+  () => componentData.goodsNumber,
+  () => {
+    getDataList();
+  }
+);
+
+watch(
+  () => componentData.goodsBrand,
+  () => {
+    getDataList();
+  }
+);
+
+watch(
+  () => componentData.goodsIds,
+  () => {
+    getDataList();
+  },
+  { deep: true } // 5. 数组变化需要 deep 监听
+);
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+
+  if (componentData.styleType == 1) style += 'flex-wrap:wrap' + ';';
+  return style;
+});
+
+const goodsCss = computed(() => {
+  let style = '';
+  if (componentData.goodsbackgroundColor) style += 'background-color:' + componentData.goodsbackgroundColor + ';';
+  //圆角
+  if (componentData.goodstopRounded) style += 'border-top-left-radius:' + componentData.goodstopRounded + 'px;';
+  if (componentData.goodstopRounded) style += 'border-top-right-radius:' + componentData.goodstopRounded + 'px;';
+  if (componentData.goodsbottomRounded) style += 'border-bottom-left-radius:' + componentData.goodsbottomRounded + 'px;';
+  if (componentData.goodsbottomRounded) style += 'border-bottom-right-radius:' + componentData.goodsbottomRounded + 'px;';
+  return style;
+});
+
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.goodsTitleColor) style += 'color:' + componentData.goodsTitleColor + ';';
+  if (componentData.goodsTitleType == 1) style += 'font-weight:bold' + ';';
+  if (componentData.goodsTitleType == 3) {
+    style += 'display: -webkit-box' + ';';
+    style += '-webkit-line-clamp: 2' + ';';
+    style += 'line-clamp: 2' + ';';
+    style += '-webkit-box-orient: vertical' + ';';
+  } else {
+    style += 'white-space:nowrap' + ';';
+  }
+  return style;
+});
+
+const btnCss1 = computed(() => {
+  let style = '';
+  if (componentData.btnbackgroundColor) style += 'background-color:' + componentData.btnbackgroundColor + ';';
+  if (componentData.btnColor) style += 'color:' + componentData.btnColor + ';';
+  return style;
+});
+
+const btnCss2 = computed(() => {
+  let style = '';
+  if (componentData.btnbackgroundColor) style += 'color:' + componentData.btnbackgroundColor + ';';
+  if (componentData.btnbackgroundColor) style += 'border-color:' + componentData.btnbackgroundColor + ';';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .goods-bos {
+    display: flex;
+    gap: 10px;
+    overflow: auto;
+    .goods-list {
+      padding: 20px 15px;
+      height: 300px;
+      width: 0;
+      flex: 0 0 calc((100% - 40px) / 5);
+      overflow: hidden;
+      .goods-img {
+        width: 100%;
+        height: 180px;
+      }
+      .itemName {
+        font-size: 14px;
+        height: 40px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+      .memberPrice {
+        font-size: 16px;
+        font-weight: bold;
+      }
+      .marketPrice {
+        font-size: 12px;
+        color: #99a1af;
+        line-height: 20px;
+        text-decoration-line: line-through;
+        text-transform: none;
+        margin-left: 6px;
+      }
+
+      .btn1 {
+        padding: 5px 15px;
+        font-size: 12px;
+        border-radius: 15px;
+      }
+      .btn2 {
+        color: var(--el-color-primary);
+        border: 1px solid var(--el-color-primary);
+        height: 26px;
+        width: 26px;
+        border-radius: 50%;
+      }
+    }
+  }
+}
+</style>

+ 285 - 0
src/views/home/pccomponents/pages/goodsList.vue

@@ -0,0 +1,285 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div :style="boxCss">
+      <div class="tab-bos flex-row-start" :style="tabCss">
+        <div v-for="(item, index) in componentData.tabList" :key="index" class="tab-list flex-row-start">
+          <div class="tab-border" v-if="index != 0"></div>
+          <div class="tab-title" :style="tabHigCss" v-if="index == componentData.tabIndex">{{ item.title || '选项卡名称' }}</div>
+          <div class="tab-title" :style="{ color: componentData.tabColor1 }" v-else>{{ item.title || '选项卡名称' }}</div>
+        </div>
+      </div>
+      <div class="goods-bos">
+        <div v-for="(item, index) in dataList" :key="index" class="goods-list flex-column-between" :style="goodsCss">
+          <img
+            class="goods-img"
+            :src="item.productImage ? item.productImage : figure"
+            alt=""
+            :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+          />
+          <div v-if="componentData.goodsShow.includes(1)" :style="titleCss" class="itemName">{{ item.itemName || '' }}</div>
+          <div class="flex-row-between">
+            <div>
+              <span v-if="componentData.goodsShow.includes(2)" class="memberPrice" :style="{ color: componentData.priceColor }"
+                >¥{{ item.memberPrice }}</span
+              >
+              <span v-if="componentData.goodsShow.includes(3)" class="marketPrice">¥{{ item.marketPrice }}</span>
+            </div>
+            <template v-if="componentData.btnShow">
+              <div v-if="componentData.btnStyle == 1" :style="btnCss1" class="btn1">{{ componentData.btnText }}</div>
+              <div v-if="componentData.btnStyle == 2" :style="btnCss2" class="btn2 flex-row-center">
+                <el-icon size="14"><Plus /></el-icon>
+              </div>
+              <div v-if="componentData.btnStyle == 3" :style="btnCss2" class="btn2 flex-row-center">
+                <icon name="iconfont icongouwuche" size="14px" />
+              </div>
+            </template>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import figure from '@/assets/images/figure.png';
+import usePcdiyStore from '@/store/modules/pcdiy';
+import { listBase } from '@/api/pmsProduct/base';
+const diyStore = usePcdiyStore();
+
+const props = defineProps<{
+  index: number; // 确保声明 index 为可选属性
+  row?: any;
+}>();
+const componentData = props.row ? props.row : diyStore.componentList[props.index];
+const dataList = ref<any>([{}, {}, {}, {}, {}]);
+
+onMounted(() => {
+  getDataList();
+});
+
+const getDataList = () => {
+  dataList.value = [{}, {}, {}, {}, {}];
+  if (componentData.tabList && componentData.tabList.length > 0) {
+    const datas = componentData.tabList[componentData.tabIndex];
+    //手动选择
+    if (datas.goodsType == 1) {
+      if (datas.goodsIds.length > 0) {
+        listBase({ pageNum: 1, pageSize: 20, ids: datas.goodsIds.join(',') }).then((res) => {
+          if (res.code == 200) {
+            dataList.value = res.rows;
+          }
+        });
+      }
+    } else if (datas.goodsType == 2) {
+      //分类查询
+      if (datas.goodsClassify) {
+        listBase({
+          pageNum: 1,
+          pageSize: datas.goodsNumber == 0 ? 50 : componentData.goodsNumber,
+          topCategoryId: datas.topCategoryId,
+          mediumCategoryId: datas.mediumCategoryId,
+          bottomCategoryId: datas.bottomCategoryId
+        }).then((res) => {
+          if (res.code == 200) {
+            dataList.value = res.rows;
+          }
+        });
+      }
+    }
+  }
+};
+
+watch(
+  () => componentData.tabIndex,
+  () => {
+    console.log('tabIndex', componentData.tabIndex);
+    getDataList();
+  }
+);
+
+watch(
+  () => componentData.tabList,
+  () => {
+    getDataList();
+  },
+  { deep: true } // 5. 数组变化需要 deep 监听
+);
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+
+  if (componentData.styleType == 1) style += 'flex-wrap:wrap' + ';';
+  return style;
+});
+
+const goodsCss = computed(() => {
+  let style = '';
+  if (componentData.goodsbackgroundColor) style += 'background-color:' + componentData.goodsbackgroundColor + ';';
+  //圆角
+  if (componentData.goodstopRounded) style += 'border-top-left-radius:' + componentData.goodstopRounded + 'px;';
+  if (componentData.goodstopRounded) style += 'border-top-right-radius:' + componentData.goodstopRounded + 'px;';
+  if (componentData.goodsbottomRounded) style += 'border-bottom-left-radius:' + componentData.goodsbottomRounded + 'px;';
+  if (componentData.goodsbottomRounded) style += 'border-bottom-right-radius:' + componentData.goodsbottomRounded + 'px;';
+  return style;
+});
+
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.goodsTitleColor) style += 'color:' + componentData.goodsTitleColor + ';';
+  if (componentData.goodsTitleType == 1) style += 'font-weight:bold' + ';';
+  if (componentData.goodsTitleType == 3) {
+    style += 'display: -webkit-box' + ';';
+    style += '-webkit-line-clamp: 2' + ';';
+    style += 'line-clamp: 2' + ';';
+    style += '-webkit-box-orient: vertical' + ';';
+  } else {
+    style += 'white-space:nowrap' + ';';
+  }
+  return style;
+});
+
+const btnCss1 = computed(() => {
+  let style = '';
+  if (componentData.btnbackgroundColor) style += 'background-color:' + componentData.btnbackgroundColor + ';';
+  if (componentData.btnColor) style += 'color:' + componentData.btnColor + ';';
+  return style;
+});
+
+const btnCss2 = computed(() => {
+  let style = '';
+  if (componentData.btnbackgroundColor) style += 'color:' + componentData.btnbackgroundColor + ';';
+  if (componentData.btnbackgroundColor) style += 'border-color:' + componentData.btnbackgroundColor + ';';
+  return style;
+});
+
+const tabCss = computed(() => {
+  let style = '';
+  if (componentData.tabbackgroundColor1) style += 'background-color:' + componentData.tabbackgroundColor1 + ';';
+  if (componentData.tabRadius) style += 'border-radius:' + componentData.tabRadius + 'px' + ';';
+  return style;
+});
+
+const tabHigCss = computed(() => {
+  let style = '';
+  if (componentData.tabbackgroundColor2) style += 'background-color:' + componentData.tabbackgroundColor2 + ';';
+  if (componentData.tabColor2) style += 'color:' + componentData.tabColor2 + ';';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .tab-bos {
+    width: 100%;
+    margin-bottom: 10px;
+    padding: 15px;
+    overflow: auto;
+    .tab-list {
+      flex-shrink: 0;
+      .tab-border {
+        width: 1px;
+        height: 15px;
+        background-color: #e5e7eb;
+        margin-left: 30px;
+      }
+      .tab-title {
+        font-size: 14px;
+        margin-left: 30px;
+        border-radius: 24px;
+        height: 24px;
+        line-height: 24px;
+        padding: 0 10px;
+      }
+    }
+  }
+  .goods-bos {
+    display: flex;
+    gap: 10px;
+    overflow: auto;
+    .goods-list {
+      padding: 20px 15px;
+      height: 300px;
+      width: 0;
+      flex: 0 0 calc((100% - 40px) / 5);
+      overflow: hidden;
+      .goods-img {
+        width: 100%;
+        height: 180px;
+      }
+      .itemName {
+        font-size: 14px;
+        height: 40px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+      .memberPrice {
+        font-size: 16px;
+        font-weight: bold;
+      }
+      .marketPrice {
+        font-size: 12px;
+        color: #99a1af;
+        line-height: 20px;
+        text-decoration-line: line-through;
+        text-transform: none;
+        margin-left: 6px;
+      }
+
+      .btn1 {
+        padding: 5px 15px;
+        font-size: 12px;
+        border-radius: 15px;
+      }
+      .btn2 {
+        color: var(--el-color-primary);
+        border: 1px solid var(--el-color-primary);
+        height: 26px;
+        width: 26px;
+        border-radius: 50%;
+      }
+    }
+  }
+}
+</style>

+ 970 - 0
src/views/home/pccomponents/pages/head.vue

@@ -0,0 +1,970 @@
+<template>
+  <div class="head-all" :style="warpCss">
+    <!-- 搜索组件 -->
+    <div class="search-bos">
+      <div class="search-content">
+        <img
+          class="logo"
+          :src="componentData.logo ? componentData.logo : logo1"
+          alt=""
+          :style="{ 'width': componentData.topStyle == 1 ? '170px' : '370px' }"
+        />
+        <div class="search-box">
+          <div class="search-div flex-row-start">
+            <div class="search-input flex-row-center">
+              <el-input class="el-input" v-model="input" placeholder="搜索商品、品牌、分类..." />
+              <div class="bnt flex-row-center" @click="onPath('/search?type=1&input=' + input)">
+                <el-icon color="#ffffff" size="20">
+                  <Search />
+                </el-icon>
+              </div>
+            </div>
+
+            <div class="cat-bos flex-row-center">
+              <el-badge :value="cartCount" v-if="cartCount > 0">
+                <img src="@/assets/images/layout/layout4.png" alt="" />
+              </el-badge>
+              <img v-else src="@/assets/images/layout/layout4.png" alt="" />
+              <span @click="onPath('/cart')" class="ml-[15px]">我的购物车</span>
+            </div>
+          </div>
+          <div class="search-text">
+            <div v-for="(item, index) in componentData.toplabel" :key="index">{{ item.title }}</div>
+          </div>
+        </div>
+        <img class="code" :src="componentData.code ? componentData.code : code" alt="" />
+      </div>
+    </div>
+    <!-- 分类 -->
+    <div class="nav-pages">
+      <div class="nav-bos">
+        <div class="nav-all flex-row-start" v-if="componentData.classifyShow">
+          <img src="@/assets/images/pcdiy/layout2.png" alt="" />
+          <div>全部商品分类</div>
+        </div>
+        <div v-for="(item, index) in componentData.topNav" :key="index" class="nav-list" :class="index == 0 ? 'hig' : ''">
+          {{ item.title }}
+        </div>
+      </div>
+    </div>
+
+    <!--  头部 -->
+    <div class="head-pages" @mouseleave="leaveClassify">
+      <div class="bg-img" v-if="componentData.carouselStyle">
+        <img :src="componentData.carouselList && componentData.carouselList[0].imageUrl" alt="" />
+      </div>
+      <div class="home-head">
+        <div
+          class="classify"
+          :class="classifyShow ? 'classify-show' : ''"
+          v-if="componentData.leftStyle == 1"
+          :style="{
+            backgroundColor: componentData.leftBackground
+          }"
+        >
+          <div
+            @mouseenter="enterClassify(item)"
+            class="classify-list"
+            v-show="classifyShow ? true : Number(index) < 13"
+            v-for="(item, index) in classifyList"
+            :key="index"
+            :class="item.id == classifyId && classifyShow ? 'classify-hig' : ''"
+          >
+            <div :style="{ 'color': componentData.leftColor1 }" class="label ellipsis hover-color">
+              {{ item.label }}
+            </div>
+            <div v-if="item.extra && item.extra.oneLable1" :style="{ 'color': componentData.leftColor2 }" class="info info1 ellipsis hover-color">
+              {{ item.extra.oneLable1 }}
+            </div>
+            <div v-if="item.extra && item.extra.oneLable2" :style="{ 'color': componentData.leftColor2 }" class="info ellipsis hover-color">
+              {{ item.extra.oneLable2 }}
+            </div>
+          </div>
+        </div>
+        <div class="classify-bos" v-if="classifyShow">
+          <div v-for="(item, index) in classifyInfo" :key="index" class="classify-item">
+            <div class="two-level ellipsis">{{ item.label || '' }}</div>
+            <el-icon class="classify-icon" :size="14" color="#364153">
+              <ArrowRight />
+            </el-icon>
+            <div class="classify-label">
+              <div v-for="(item1, index1) in item.children" :key="index1">{{ item1.label || '' }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="classify2" v-if="componentData.leftStyle == 2">
+          <div class="classify-list" v-for="(item, index) in classifyList" :key="index">
+            <div class="label ellipsis">{{ item.label }}</div>
+            <div class="two-level">
+              <template v-for="(item1, index1) in item.children" :key="index1">
+                <div class="two-hig" v-if="Number(index1) < 2">{{ item1.label }}</div>
+                <div style="margin: 0 4px" v-if="index1 == 0 && item.children.length > 1">/</div>
+              </template>
+            </div>
+          </div>
+        </div>
+        <div class="head-bos">
+          <div
+            class="carousel"
+            :class="[
+              { 'carousel-type': componentData.carouselType == 2 },
+              'position' + componentData.carouselPosition,
+              'styleType' + componentData.carouselStyleType
+            ]"
+            :style="{
+              height: componentData.advertNum == 0 ? '540px' : '400px',
+              borderRadius: componentData.carouselRadius + 'px'
+            }"
+          >
+            <el-carousel :height="componentData.advertNum == 0 ? '540px' : '400px'" arrow="always">
+              <template v-if="componentData.carouselList && componentData.carouselList.length > 0">
+                <el-carousel-item v-for="item in componentData.carouselList" :key="item">
+                  <el-image
+                    style="width: 100%; height: 100%"
+                    :src="item.imageUrl ? item.imageUrl : figure"
+                    :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+                  />
+                </el-carousel-item>
+              </template>
+              <template v-else>
+                <el-carousel-item>
+                  <el-image style="width: 100%; height: 100%" :src="figure" fit="cover" />
+                </el-carousel-item>
+              </template>
+            </el-carousel>
+          </div>
+          <div class="head-box" v-if="componentData.advertNum != 0">
+            <template v-for="(item, index) in diyStore.editComponent.advertList" :key="index">
+              <div class="head-item" v-if="item.show">
+                <el-image
+                  style="width: 100%; height: 100%"
+                  :src="item.imageUrl ? item.imageUrl : figure"
+                  :fit="item.imageUrl ? (item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover') : 'cover'"
+                />
+              </div>
+            </template>
+          </div>
+        </div>
+        <!-- 右边 -->
+        <div
+          class="head-right"
+          :style="{
+            borderRadius: componentData.rightRadius + 'px'
+          }"
+        >
+          <div v-if="userInfo.userId" class="order-bos flex-column-between">
+            <div class="flex-row-start">
+              <img :src="logo2" alt="" />
+              <div class="ellipsis">{{ userInfo.nickName }}</div>
+            </div>
+            <div class="flex-row-start">
+              <div class="flex-1 flex-column-center">
+                <div>待付款</div>
+                <div class="order-num">{{ countData.pendingPaymentCount || 0 }}</div>
+              </div>
+              <div class="flex-1 flex-column-center">
+                <div>待发货</div>
+                <div class="order-num">{{ countData.pendingShipmentCount || 0 }}</div>
+              </div>
+              <div class="flex-1 flex-column-center">
+                <div>待收货</div>
+                <div class="order-num">{{ countData.pendingReceiptCount || 0 }}</div>
+              </div>
+            </div>
+          </div>
+          <div class="login-bos" v-else>
+            <div class="login-box">
+              <img :src="logo2" alt="" />
+              <div>
+                <div class="login1">您好,欢迎来到优易达</div>
+                <div class="login2">请先登录</div>
+              </div>
+            </div>
+            <div class="loginBtn-bos flex-row-center">
+              <div class="login-bnt1 flex-row-center" @click="onPath('/login')">登录</div>
+              <div class="login-bnt2 flex-row-center" @click="onPath('/breg')">注册</div>
+            </div>
+          </div>
+          <div class="real-time">
+            <div class="real-title flex-row-between">
+              <div class="real1">优易资讯</div>
+              <div class="real2 flex-row-start">
+                <div class="hover-color">更多</div>
+                <el-icon :size="13" color="#83899F">
+                  <ArrowRight />
+                </el-icon>
+              </div>
+            </div>
+            <template v-for="(item, index) in realList" :key="index">
+              <div
+                @click="onPath('/solve/real?id=' + item.id)"
+                class="real-list ellipsis hover-color"
+                v-if="componentData.realDataType == 2 ? true : Number(index) < componentData.realNumber"
+              >
+                {{ item.announcementTitle }}
+              </div>
+            </template>
+          </div>
+          <div class="interests">
+            <div class="interests-title">企业会员权益</div>
+            <div class="interests-bos">
+              <div v-for="(item, index) in componentData.navlList" :key="index" class="interests-item flex-column-center">
+                <el-image
+                  class="img"
+                  :src="item.imageUrl ? item.imageUrl : figure"
+                  :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+                />
+                <div style="height: 18px" class="hover-color">{{ item.title }}</div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup name="Index" lang="ts">
+import figure from '@/assets/images/figure.png';
+import logo1 from '@/assets/images/pcdiy/logo1.png';
+import logo2 from '@/assets/images/pcdiy/logo2.png';
+import code from '@/assets/images/pcdiy/code.png';
+import {
+  getProductCategoryTree,
+  getHomeAdList,
+  getYouYiZiXunPage,
+  getEnterpriseMemberEquityList,
+  getHomeThreeAdList,
+  getHotSchemeTitle,
+  getHotSchemeList,
+  getScenePurchaseTitle,
+  getScenePurchaseList,
+  getPlatformFlashSaleTitle,
+  getPlatformFlashSaleList,
+  getPlatformFlashSaleBrand,
+  getExpertSelectionTitle,
+  getProcurementTopicsList,
+  getPurchaseGuideTitle,
+  getExpertSelectionList,
+  getClassificationFloorList,
+  getClassificationFloorDetail,
+  getClassificationFloorLabel,
+  getClassificationFloorDetail2,
+  getProjectCaseTitle,
+  getProjectCaseList,
+  countOrder
+} from '@/api/home/index';
+import { getAnnouncementPage } from '@/api/home/diy';
+import { onPath } from '@/utils/siteConfig';
+import Cookies from 'js-cookie';
+import { getInfo } from '@/api/login';
+import { cartStore } from '@/store/modules/cart';
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+const userInfo = ref<any>({});
+const countData = ref<any>({});
+//左侧分类
+const classifyList = ref<any>([]);
+const realList = ref<any>([]);
+const classifyShow = ref<any>(false);
+const classifyId = ref<any>('');
+const classifyInfo = ref<any>([]);
+const cartStoreData = cartStore();
+const cartCount = computed(() => cartStoreData.cartCount);
+const input = ref<any>('');
+
+document.documentElement.style.setProperty('--carousel-color', componentData.carouselStyleColor ? componentData.carouselStyleColor : '#ffffff');
+onMounted(() => {
+  getDataList();
+  const token = Cookies.get('Authorization');
+  if (token) {
+    getInfo().then((res) => {
+      if (res.code == 200) {
+        userInfo.value = res.data.user;
+
+        countOrder({}).then((res1) => {
+          if (res1.code == 200) {
+            countData.value = res1.data || {};
+          }
+        });
+      }
+    });
+  }
+});
+
+//头部分类
+getProductCategoryTree({ platform: 0 }).then((res) => {
+  if (res.code == 200) {
+    classifyList.value = res.data;
+  }
+});
+
+const getDataList = () => {
+  realList.value = [];
+  // 默认
+  if (componentData.realDataType == 1) {
+    getAnnouncementPage({ pageSize: 20 }).then((res) => {
+      if (res.code == 200) {
+        realList.value = res.rows;
+      }
+    });
+  } else {
+    //手动选择
+    getAnnouncementPage({ pageSize: 20, ids: componentData.realIds.join(',') }).then((res) => {
+      if (res.code == 200) {
+        const result = res.rows.filter((item: any) => componentData.realIds.includes(item.id));
+        realList.value = result;
+      }
+    });
+  }
+};
+
+//移入分类
+const enterClassify = (res: any) => {
+  classifyShow.value = true;
+  classifyId.value = res.id;
+  classifyInfo.value = res.children;
+};
+
+//移出分类
+const leaveClassify = () => {
+  classifyShow.value = false;
+};
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.head-all {
+  width: 100%;
+
+  // 搜索栏
+  .search-bos {
+    width: 100%;
+    background-color: #ffffff;
+
+    .search-content {
+      margin: 0 auto;
+      width: 1200px;
+      display: flex;
+      padding: 0 30px;
+    }
+
+    .logo {
+      width: 170px;
+      height: 88px;
+      border-radius: 4px;
+      margin-top: 10px;
+      margin-right: 30px;
+    }
+
+    .search-box {
+      flex: 1;
+      height: 88px;
+      padding-top: 40px;
+
+      .search-div {
+        .search-input {
+          flex: 1;
+          height: 38px;
+          border-radius: 3px;
+          border: 2px solid #fb2c36;
+          padding-right: 4px;
+          font-size: 14px;
+
+          .el-input {
+            height: 30px;
+            width: 100%;
+            font-size: 16px;
+
+            :deep(.el-input__wrapper) {
+              border: none;
+              /* 可选:去除聚焦时的高亮 */
+              box-shadow: none;
+              outline: none;
+            }
+          }
+
+          .bnt {
+            width: 50px;
+            height: 30px;
+            background: #e7000b;
+            border-radius: 3px;
+            font-weight: bold;
+            cursor: pointer;
+          }
+        }
+
+        .cat-bos {
+          width: 143px;
+          height: 38px;
+          background: #ffffff;
+          border-radius: 10px;
+          border: 1px solid #e5e7eb;
+          margin-left: 24px;
+          font-size: 14px;
+          color: #e7000b;
+          cursor: pointer;
+
+          img {
+            width: 14px;
+            height: 14px;
+            margin-top: 2px;
+          }
+        }
+      }
+
+      .search-text {
+        font-size: 12px;
+        color: #e7000b;
+        display: flex;
+        margin-top: 4px;
+
+        div {
+          margin-left: 10px;
+        }
+      }
+    }
+
+    .code {
+      height: 90px;
+      width: 90px;
+      margin-top: 10px;
+      margin-left: 70px;
+      // border-radius: 4px;
+    }
+  }
+
+  //分类
+  .nav-pages {
+    width: 100%;
+    background-color: #ffffff;
+
+    .nav-bos {
+      margin: 0 auto;
+      width: 1200px;
+      display: flex;
+      position: relative;
+      padding-top: 15px;
+
+      .nav-all {
+        width: 234px;
+        height: 40px;
+        background: #e7000b;
+        padding: 0 10px;
+        font-size: 15px;
+        color: #ffffff;
+        cursor: pointer;
+
+        img {
+          height: 16px;
+          width: 16px;
+          margin-right: 6px;
+        }
+      }
+
+      .nav-list {
+        line-height: 40px;
+        font-size: 15px;
+        color: #364153;
+        margin: 0 16px;
+        text-align: center;
+        cursor: pointer;
+
+        &.hig {
+          color: #e7000b;
+          position: relative;
+
+          &::before {
+            content: '';
+            position: absolute;
+            bottom: 0;
+            left: 0px;
+            display: inline-block;
+            width: 100%;
+            height: 3px;
+            background: #e7000b;
+            margin-right: 8px;
+          }
+        }
+
+        &:hover {
+          color: #e7000b;
+        }
+      }
+    }
+  }
+
+  // 头部
+  .head-pages {
+    width: 1200px;
+    margin: 0 auto;
+    background-size: 100% 100%;
+    background-repeat: no-repeat;
+    position: relative;
+    backdrop-filter: blur(95px);
+    filter: blur(30rpx);
+
+    .bg-img {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      top: 0;
+      z-index: -1;
+      filter: blur(30rpx);
+      overflow: hidden;
+
+      img {
+        width: 100%;
+        height: 100%;
+        transform: scale(1.2);
+        filter: blur(30px);
+      }
+    }
+
+    .home-head {
+      width: 1200px;
+      position: relative;
+      display: flex;
+      gap: 0px 10px;
+      margin: 10px auto 0 auto;
+
+      .classify {
+        width: 234px;
+        height: 540px;
+        background: #ffffff;
+        border-radius: 5px;
+
+        &.classify-show {
+          position: absolute;
+          z-index: 999;
+          height: auto;
+          min-height: 540px;
+        }
+
+        .classify-list {
+          width: 100%;
+          height: 40px;
+          cursor: pointer;
+          display: flex;
+          align-items: center;
+          padding-left: 15px;
+          position: relative;
+
+          &.classify-hig {
+            border: 1px solid var(--el-color-primary);
+            border-right: 0px solid var(--el-color-primary);
+          }
+
+          .label {
+            max-width: 100px;
+            font-weight: 600;
+            font-size: 14px;
+            color: #101828;
+            white-space: nowrap;
+            margin-right: 10px;
+
+            &:hover {
+              color: #e7000b;
+            }
+          }
+
+          .info {
+            max-width: 60px;
+            font-size: 12px;
+            color: #364153;
+            white-space: nowrap;
+
+            &.info1 {
+              margin-right: 6px;
+            }
+
+            &:hover {
+              color: #e7000b;
+            }
+          }
+
+          .classify-border {
+            position: absolute;
+            right: -1px;
+            top: 0px;
+            width: 1px;
+            height: 38px;
+            background-color: #ffffff;
+            z-index: 2;
+          }
+        }
+      }
+      .classify-bos {
+        position: absolute;
+        top: 0;
+        right: 0;
+        width: 966px;
+        height: 100%;
+        border: 1px solid var(--el-color-primary);
+        background-color: #ffffff;
+        overflow-y: auto;
+        padding-left: 30px;
+        z-index: 999;
+
+        .classify-item {
+          display: flex;
+          padding-top: 10px;
+          border-bottom: 1px solid #e5e7eb;
+
+          .two-level {
+            width: 90px;
+            font-size: 14px;
+            color: var(--el-color-primary);
+            cursor: pointer;
+          }
+
+          .classify-icon {
+            margin: 4px 15px 0 15px;
+          }
+
+          .classify-label {
+            display: flex;
+            flex-wrap: wrap;
+            flex: 1;
+            font-size: 14px;
+            color: #364153;
+
+            div {
+              margin-right: 20px;
+              margin-bottom: 10px;
+              cursor: pointer;
+
+              &:hover {
+                color: var(--el-color-primary);
+              }
+            }
+          }
+        }
+      }
+
+      .classify2 {
+        width: 234px;
+        height: 540px;
+        background: #ffffff;
+        padding: 10px 0px;
+
+        .classify-list {
+          width: 100%;
+          height: 60px;
+          cursor: pointer;
+          position: relative;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          padding-left: 25px;
+
+          &.classify-hig {
+            border: 1px solid var(--el-color-primary);
+            border-right: 0px solid var(--el-color-primary);
+          }
+
+          .label {
+            width: 100%;
+            font-size: 14px;
+            color: #101828;
+            white-space: nowrap;
+            margin-right: 10px;
+            font-weight: 600;
+
+            &:hover {
+              color: var(--el-color-primary);
+            }
+          }
+
+          .two-level {
+            display: flex;
+            align-items: center;
+            font-size: 12px;
+            color: #364153;
+            margin-top: 6px;
+
+            .two-hig {
+              &:hover {
+                color: var(--el-color-primary);
+              }
+            }
+          }
+        }
+      }
+
+      // 头部中间
+      .head-bos {
+        flex: 1;
+
+        .carousel {
+          overflow: hidden;
+          width: 100%;
+          background: #ffffff;
+          cursor: pointer;
+
+          :deep(.el-carousel__button) {
+            background-color: var(--carousel-color);
+          }
+
+          &.carousel-type {
+            :deep(.el-carousel__arrow) {
+              border-radius: 0;
+            }
+          }
+
+          &.position1 {
+            :deep(.el-carousel__indicators--horizontal) {
+              left: 5%;
+            }
+          }
+          &.position2 {
+            :deep(.el-carousel__indicators--horizontal) {
+              left: 50%;
+            }
+          }
+          &.position3 {
+            :deep(.el-carousel__indicators--horizontal) {
+              left: 95%;
+            }
+          }
+          &.styleType2 {
+            :deep(.el-carousel__button) {
+              height: 10px;
+              width: 10px;
+              border-radius: 10px;
+            }
+          }
+        }
+
+        .head-box {
+          width: 740px;
+          height: 130px;
+          margin-top: 10px;
+          display: flex;
+          gap: 0 10px;
+
+          .head-item {
+            flex: 1;
+            background-color: #ffffff;
+            height: 130px;
+            display: flex;
+            align-items: center;
+            cursor: pointer;
+            border-radius: 5px;
+            overflow: hidden;
+
+            img {
+              width: 100%;
+              height: 100%;
+            }
+          }
+        }
+      }
+
+      //右边
+      .head-right {
+        width: 210px;
+        height: 540px;
+        background: #ffffff;
+        display: flex;
+        flex-direction: column;
+        font-size: 14px;
+        .order-bos {
+          width: calc(100% - 20px);
+          height: 110px;
+          font-size: 14px;
+          padding: 16px 0;
+          border-bottom: 1px solid #e5e7eb;
+          margin: 0 10px;
+          img {
+            width: 28px;
+            height: 28px;
+          }
+          .order-num {
+            color: #e7000b;
+            font-size: 14px;
+            margin-top: 2px;
+          }
+        }
+
+        .login-bos {
+          width: calc(100% - 20px);
+          height: 110px;
+          border-bottom: 1px solid #e5e7eb;
+          margin: 0 10px;
+          display: flex;
+          flex-direction: column;
+          justify-content: space-between;
+          padding: 16px 0;
+
+          .login-box {
+            display: flex;
+            align-items: center;
+
+            img {
+              width: 40px;
+              height: 40px;
+              margin-right: 8px;
+              border-radius: 40px;
+            }
+
+            .login1 {
+              font-size: 13px;
+              color: #444444;
+            }
+
+            .login2 {
+              margin-top: 2px;
+              font-size: 12px;
+              color: #6a7282;
+            }
+          }
+
+          .loginBtn-bos {
+            width: 100%;
+
+            .login-bnt1 {
+              width: 64px;
+              height: 24px;
+              background-color: #e7000b;
+              color: #ffffff;
+              border-radius: 24px;
+              font-size: 12px;
+              cursor: pointer;
+            }
+
+            .login-bnt2 {
+              width: 64px;
+              height: 24px;
+              border: 1px solid #e7000b;
+              color: #e7000b;
+              border-radius: 24px;
+              font-size: 12px;
+              margin-left: 10px;
+              cursor: pointer;
+            }
+          }
+        }
+
+        .real-time {
+          width: calc(100% - 20px);
+          // height: 230px;
+          border-bottom: 1px solid #e5e7eb;
+          margin: 0 10px;
+          padding-top: 15px;
+
+          .real-title {
+            position: relative;
+            margin-bottom: 12px;
+
+            &::after {
+              content: '';
+              top: 3px;
+              left: 0;
+              position: absolute;
+              width: 4px;
+              height: 14px;
+              background: #e7000b;
+            }
+
+            .real1 {
+              font-weight: 600;
+              font-size: 14px;
+              color: #1d2129;
+              padding-left: 15px;
+            }
+
+            .real2 {
+              font-size: 13px;
+              color: #83899f;
+              cursor: pointer;
+            }
+          }
+
+          .real-list {
+            width: 100%;
+            font-size: 12px;
+            color: #1d2129;
+            margin-bottom: 12px;
+            cursor: pointer;
+          }
+        }
+
+        .interests {
+          flex: 1;
+          width: calc(100% - 20px);
+          margin: 0 10px;
+          padding-top: 15px;
+
+          .interests-title {
+            position: relative;
+            font-weight: 600;
+            font-size: 14px;
+            color: #1d2129;
+            padding-left: 15px;
+
+            &::after {
+              content: '';
+              top: 3px;
+              left: 0;
+              position: absolute;
+              width: 4px;
+              height: 14px;
+              background: #e7000b;
+            }
+          }
+
+          .interests-bos {
+            display: flex;
+            flex-wrap: wrap;
+
+            .interests-item {
+              width: 33.333%;
+              font-size: 12px;
+              color: #101828;
+              margin-top: 15px;
+              cursor: pointer;
+
+              .img {
+                width: 34px;
+                height: 34px;
+                border-radius: 6px;
+                margin-bottom: 7px;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+</style>

+ 89 - 0
src/views/home/pccomponents/pages/hot.vue

@@ -0,0 +1,89 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <el-image class="hot-image" :src="componentData.imageUrl ? componentData.imageUrl : figure" fit="fill" />
+    <div
+      @click="onClick(mapItem)"
+      class="absolute hot-aaaaaa"
+      v-for="(mapItem, mapIndex) in componentData.heatMapData"
+      :key="mapIndex"
+      :style="{ width: mapItem.width + '%', height: mapItem.height + '%', left: mapItem.left + '%', top: mapItem.top + '%' }"
+    ></div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import usePcdiyStore from '@/store/modules/pcdiy';
+import figure from '@/assets/images/figure.png';
+const diyStore = usePcdiyStore();
+
+const props = defineProps<{
+  index: number; // 确保声明 index 为可选属性
+  row?: any;
+}>();
+
+const onClick = (mapItem: any) => {};
+const componentData = props.row ? props.row : diyStore.componentList[props.index];
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  position: relative;
+
+  .hot-image {
+    width: 100%;
+
+
+  }
+
+  .hot-aaaaaa {
+      border: 1px red solid;
+      z-index: 10;
+    }
+}
+</style>

+ 102 - 0
src/views/home/pccomponents/pages/imageCube.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="pcPages" :style="warpCss">
+    <div class="imageCube-bos" :style="{ gap: componentData.gap + 'px' }">
+      <template v-for="(item, index) in componentData.imagelList" :key="index">
+        <div v-if="index < componentData.number" class="imageCube-list" :style="boxCss">
+          <el-image
+            class="img"
+            :src="item.imageUrl ? item.imageUrl : figure"
+            :fit="item.imageUrl ? (item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover') : 'cover'"
+            :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+          />
+        </div>
+      </template>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import figure from '@/assets/images/figure.png';
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  // 宽度
+  if (componentData.number)
+    style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * componentData.gap}px) / ${componentData.number})` + ';';
+  //圆角
+  if (componentData.imageTopRounded) style += 'border-top-left-radius:' + componentData.imageTopRounded + 'px;';
+  if (componentData.imageTopRounded) style += 'border-top-right-radius:' + componentData.imageTopRounded + 'px;';
+  if (componentData.imageBottomRoundedRounded) style += 'border-bottom-left-radius:' + componentData.imageBottomRoundedRounded + 'px;';
+  if (componentData.imageBottomRoundedRounded) style += 'border-bottom-right-radius:' + componentData.imageBottomRoundedRounded + 'px;';
+  //高度
+  if (componentData.imageHeight) style += 'height:' + componentData.imageHeight + 'px;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .imageCube-bos {
+    display: flex;
+    .imageCube-list {
+      overflow: hidden;
+      .img {
+        width: 100%;
+        height: 100%;
+        cursor: pointer;
+      }
+    }
+  }
+}
+</style>

+ 160 - 0
src/views/home/pccomponents/pages/navigation.vue

@@ -0,0 +1,160 @@
+<template>
+  <div class="pcPages">
+    <div class="carousel-bos" :style="warpCss" v-if="componentData.styleType == 3">
+      <el-carousel :height="170 * componentData.count + (componentData.count == 2 ? 10 : 0) + 'px'" :autoplay="false" arrow="always">
+        <el-carousel-item v-for="(item1, index1) in dataList" :key="index1" class="w100% h100%">
+          <div class="carousel-list">
+            <div v-for="(item, index) in item1" :key="index" class="data-list flex-column-center hover-color" :style="boxCss">
+              <div :style="titleCss" class="zi-hover">{{ item.title || '' }}</div>
+              <div :style="subtitleCss" class="mt-[2px] mb-[12px]">{{ item.subtitle || '' }}</div>
+              <el-image
+                class="img"
+                :src="item.imageUrl ? item.imageUrl : figure"
+                :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+                :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+              />
+            </div>
+          </div>
+        </el-carousel-item>
+      </el-carousel>
+    </div>
+    <div v-else :style="warpCss" class="data-bos">
+      <div v-for="(item, index) in componentData.navlList" :key="index" class="data-list flex-column-center hover-color" :style="boxCss">
+        <div :style="titleCss" class="zi-hover">{{ item.title || '' }}</div>
+        <div :style="subtitleCss" class="mt-[2px] mb-[12px]">{{ item.subtitle || '' }}</div>
+        <el-image
+          class="img"
+          :src="item.imageUrl ? item.imageUrl : figure"
+          :fit="item.imgType == 1 ? 'fill' : item.imgType == 2 ? 'contain' : 'cover'"
+          :style="componentData.imageRadius ? { borderRadius: componentData.imageRadius + 'px' } : {}"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import figure from '@/assets/images/figure.png';
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+
+const dataList = computed(() => {
+  const chunkSize = componentData.number * componentData.count;
+  const result = [];
+  for (let i = 0; i < componentData.navlList.length; i += chunkSize) {
+    const chunk = componentData.navlList.slice(i, i + chunkSize);
+    result.push(chunk);
+  }
+  return result;
+});
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+    if (componentData.styleType == 1) style += 'flex-wrap:wrap' + ';';
+  }
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  if (componentData.number) style += 'flex:' + `0 0 calc((100% - ${(componentData.number - 1) * 10}px) / ${componentData.number})` + ';';
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+  return style;
+});
+
+// 标题样式
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
+  if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
+  if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
+  return style;
+});
+
+// 副标题样式
+const subtitleCss = computed(() => {
+  let style = '';
+  if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
+  if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+  .data-bos {
+    display: flex;
+    gap: 10px;
+    width: 100%;
+    overflow-x: auto;
+    .data-list {
+      min-height: 170px;
+      cursor: pointer;
+
+      .img {
+        height: 80px;
+        width: 80px;
+      }
+    }
+  }
+
+  .carousel-bos {
+    .carousel-list {
+      width: 100%;
+      height: 100%;
+      display: flex;
+      gap: 10px;
+      flex-wrap: wrap;
+      .data-list {
+        height: 170px;
+
+        .img {
+          height: 80px;
+          width: 80px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 465 - 0
src/views/home/pccomponents/pages/textTitle.vue

@@ -0,0 +1,465 @@
+<template>
+  <div class="pcPages">
+    <div :style="warpCss">
+      <!-- 风格1 -->
+      <div :style="boxCss" v-if="componentData.styleType == 1">
+        <div class="hover-color" :style="titleCss">{{ componentData.title }}{{ componentData.titleUrl }}</div>
+      </div>
+      <!-- 风格2 -->
+      <div :style="boxCss" class="style2 flex-row-center" v-else-if="componentData.styleType == 2">
+        <div class="style2-border" :style="{ backgroundColor: componentData.titleColor }"></div>
+        <div class="style2-text hover-color" :style="titleCss">{{ componentData.title }}</div>
+        <div class="style2-border" :style="{ backgroundColor: componentData.titleColor }"></div>
+      </div>
+      <!-- 风格3 -->
+      <div :style="boxCss" class="style3 flex-column-center" v-else-if="componentData.styleType == 3">
+        <div :style="titleCss" class="mb-[4px] hover-color">{{ componentData.title }}</div>
+        <div class="style3-border" :style="{ backgroundColor: componentData.titleColor }"></div>
+        <div class="style3-jiao" :style="{ borderColor: componentData.titleColor }"></div>
+      </div>
+      <!-- 风格4 -->
+      <div :style="boxCss" class="style4 flex-column-center" v-else-if="componentData.styleType == 4">
+        <div :style="titleCss" class="mb-[4px] hover-color">{{ componentData.title }}</div>
+        <div class="style4-border1" :style="{ backgroundColor: componentData.titleColor }"></div>
+        <div class="style4-border2" :style="{ backgroundColor: componentData.titleColor }"></div>
+      </div>
+      <!-- 风格5 -->
+      <div :style="boxCss" class="style5 flex-column-center" v-else-if="componentData.styleType == 5">
+        <div :style="titleCss" class="mb-[4px] hover-color">{{ componentData.title }}</div>
+        <div class="flex-row-center">
+          <div class="style5-border" :style="{ backgroundColor: componentData.titleColor }"></div>
+          <div class="style5-box" :style="{ borderColor: componentData.titleColor }"></div>
+          <div class="style5-border" :style="{ backgroundColor: componentData.titleColor }"></div>
+        </div>
+      </div>
+      <!-- 风格6 -->
+      <div :style="boxCss" class="style6 flex-column-center" v-else-if="componentData.styleType == 6">
+        <div class="style6-bos flex-row-center" :style="{ borderColor: componentData.titleColor }">
+          <div class="style6-border style6-border1" :style="{ backgroundColor: componentData.titleColor }"></div>
+          <div :style="titleCss" class="style6-box hover-color">{{ componentData.title }}</div>
+          <div class="style6-border style6-border2" :style="{ backgroundColor: componentData.titleColor }"></div>
+        </div>
+      </div>
+      <!-- 风格7 -->
+      <div :style="boxCss" class="style7 flex-column-center" v-else-if="componentData.styleType == 7">
+        <div class="style7-bos">
+          <div class="style7-text hover-color" :style="titleCss">{{ componentData.title }}</div>
+          <div class="style7-line" :style="{ borderColor: componentData.titleColor }"></div>
+        </div>
+      </div>
+      <!-- 风格8 -->
+      <div :style="boxCss" class="style8 flex-column-center" v-else-if="componentData.styleType == 8">
+        <div class="style8-bos">
+          <div class="style8-text hover-color" :style="titleCss">{{ componentData.title }}</div>
+          <div class="style8-line" :style="{ borderColor: componentData.titleColor }"></div>
+        </div>
+      </div>
+      <!-- 风格9 -->
+      <div :style="boxCss" class="style9 flex-row-start" v-else-if="componentData.styleType == 9">
+        <div class="style9-border" :style="{ backgroundColor: componentData.titleColor }"></div>
+        <div class="pl-[10px] hover-color" :style="titleCss">{{ componentData.title }}</div>
+      </div>
+      <!-- 风格10 -->
+      <div :style="boxCss" class="style10 flex-column-center" v-else-if="componentData.styleType == 10">
+        <div class="style10-bos flex-row-start">
+          <img class="style10-img1" src="@/assets/images/pcdiy/style10-1.png" alt="" />
+          <div :style="titleCss" class="hover-color">{{ componentData.title }}</div>
+          <img class="style10-img2" src="@/assets/images/pcdiy/style10-2.png" alt="" />
+        </div>
+        <div class="mt-[2px]" :style="subtitleCss">
+          {{ componentData.subtitle }}
+        </div>
+      </div>
+      <!-- 风格11 -->
+      <div :style="boxCss" class="style11 flex-column-center" v-else-if="componentData.styleType == 11">
+        <div class="style11-bos flex-row-start">
+          <img class="style11-img style11-img1" src="@/assets/images/pcdiy/style11-1.png" alt="" />
+          <div :style="titleCss" class="style11-text hover-color">{{ componentData.title }}</div>
+          <img class="style11-img style11-img2" src="@/assets/images/pcdiy/style11-2.png" alt="" />
+          <img class="style11-img3" src="@/assets/images/pcdiy/style11-3.png" alt="" />
+        </div>
+        <div class="mt-[2px]" :style="subtitleCss">
+          {{ componentData.subtitle }}
+        </div>
+      </div>
+      <!-- 风格12 -->
+      <div :style="boxCss" class="style12 flex-row-between" v-else-if="componentData.styleType == 12">
+        <div class="flex-row-start">
+          <div :style="titleCss" class="hover-color">{{ componentData.title }}</div>
+          <div :style="subtitleCss" class="ml-[5px]">{{ componentData.subtitle }}</div>
+        </div>
+        <div v-if="componentData.moreShow" class="flex-row-start hover-color" :style="moreCss">
+          <div>{{ componentData.more }}</div>
+          <el-icon><ArrowRight /></el-icon>
+        </div>
+      </div>
+      <!-- 风格13 -->
+      <div :style="boxCss" class="style13 flex-column-center" v-else-if="componentData.styleType == 13">
+        <div class="style13-bos flex-row-start">
+          <img class="style13-img1" src="@/assets/images/pcdiy/style13-1.png" alt="" />
+          <div :style="titleCss" class="hover-color">{{ componentData.title }}</div>
+          <img class="style13-img2" src="@/assets/images/pcdiy/style13-2.png" alt="" />
+        </div>
+      </div>
+      <!-- 风格14 -->
+      <div :style="boxCss" class="style14 flex-row-between" v-else-if="componentData.styleType == 14">
+        <div>
+          <div :style="titleCss" class="hover-color">{{ componentData.title }}</div>
+          <div :style="subtitleCss">{{ componentData.subtitle }}</div>
+        </div>
+        <div v-if="componentData.moreShow" class="flex-row-start hover-color" :style="moreCss">
+          <div>{{ componentData.more }}</div>
+          <el-icon><ArrowRight /></el-icon>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup name="Index" lang="ts">
+interface Props {
+  row?: any;
+}
+const props = defineProps<Props>();
+const componentData = props.row || {};
+
+const warpCss = computed(() => {
+  let style = '';
+  style += 'position:relative;';
+  //背景颜色
+  if (componentData.pageStartBgColor) {
+    if (componentData.pageStartBgColor && componentData.pageEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.pageStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.pageStartBgColor) style += `background: ${componentData.pageStartBgColor};`;
+    else if (componentData.pageEndBgColor) style += `background: ${componentData.pageEndBgColor};`;
+  }
+  //背景图片
+  if (componentData.componentBgUrl) {
+    style += `background-image:url('${componentData.componentBgUrl}');`;
+    style += 'background-size: cover;background-repeat: no-repeat;';
+  }
+  //边距
+  if (componentData.padding) {
+    if (componentData.padding.top > 0) {
+      style += 'padding-top:' + componentData.padding.top + 'px' + ';';
+    }
+    if (componentData.padding.bottom > 0) {
+      style += 'padding-bottom:' + componentData.padding.bottom + 'px' + ';';
+    }
+    style += 'padding-right:' + componentData.padding.both + 'px' + ';';
+    style += 'padding-left:' + componentData.padding.both + 'px' + ';';
+  }
+  //圆角
+  if (componentData.topRounded) style += 'border-top-left-radius:' + componentData.topRounded + 'px;';
+  if (componentData.topRounded) style += 'border-top-right-radius:' + componentData.topRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-left-radius:' + componentData.bottomRounded + 'px;';
+  if (componentData.bottomRounded) style += 'border-bottom-right-radius:' + componentData.bottomRounded + 'px;';
+
+  //间距
+  if (componentData.margin) {
+    if (componentData.margin.top > 0) {
+      style += 'margin-top:' + componentData.margin.top + 'px' + ';';
+    }
+    if (componentData.margin.bottom > 0) {
+      style += 'margin-bottom:' + componentData.margin.bottom + 'px' + ';';
+    }
+  }
+
+  return style;
+});
+
+//组件样式
+const boxCss = computed(() => {
+  let style = '';
+  if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+    style += `background:linear-gradient(${componentData.componentGradientAngle},${componentData.componentStartBgColor},${componentData.componentEndBgColor});`;
+  else if (componentData.componentStartBgColor) style += 'background-color:' + componentData.componentStartBgColor + ';';
+  else if (componentData.componentEndBgColor) style += 'background-color:' + componentData.componentEndBgColor + ';';
+  return style;
+});
+
+// 标题样式
+const titleCss = computed(() => {
+  let style = '';
+  if (componentData.titleColor) style += 'color:' + componentData.titleColor + ';';
+  if (componentData.titleSize) style += 'font-size:' + componentData.titleSize + 'px;';
+  if (componentData.titleWeight) style += 'font-weight:' + componentData.titleWeight + ';';
+  if (componentData.titleAlign && componentData.styleType == 1) style += 'text-align:' + componentData.titleAlign;
+  if (componentData.titleColor && (componentData.styleType == 6 || componentData.styleType == 7)) {
+    style += 'border-color:' + componentData.titleColor;
+  }
+  if (componentData.titleColor && componentData.styleType == 8) {
+    style += 'background-color:' + componentData.titleColor;
+  }
+  return style;
+});
+
+// 副标题样式
+const subtitleCss = computed(() => {
+  let style = '';
+  if (componentData.subtitleColor) style += 'color:' + componentData.subtitleColor + ';';
+  if (componentData.subtitleSize) style += 'font-size:' + componentData.subtitleSize + 'px;';
+  return style;
+});
+
+// 更多样式
+const moreCss = computed(() => {
+  let style = '';
+  if (componentData.moreColor) style += 'color:' + componentData.moreColor + ';';
+  if (componentData.moreSize) style += 'font-size:' + componentData.moreSize + 'px;';
+  return style;
+});
+
+// 背景图加遮罩层
+const maskLayer = computed(() => {
+  let style = '';
+  //背景颜色
+  if (componentData.componentStartBgColor) {
+    if (componentData.componentStartBgColor && componentData.componentEndBgColor)
+      style += `background:linear-gradient(${componentData.pageGradientAngle},${componentData.componentStartBgColor},${componentData.pageEndBgColor});`;
+    else if (componentData.componentStartBgColor) style += `background: ${componentData.componentStartBgColor};`;
+    else if (componentData.componentEndBgColor) style += `background: ${componentData.componentEndBgColor};`;
+  }
+
+  return style;
+});
+</script>
+
+<style lang="scss" scoped>
+.pcPages {
+  width: 1200px;
+  margin: 0 auto;
+
+  .style2 {
+    .style2-text {
+      margin: 0 30px;
+    }
+
+    .style2-border {
+      width: 160px;
+      height: 1px;
+    }
+  }
+
+  .style3 {
+    position: relative;
+
+    .style3-border {
+      width: 260px;
+      height: 1px;
+    }
+
+    .style3-jiao {
+      background: transparent !important;
+      display: inline-block;
+      border: 6px solid #cccccc;
+      border-top-color: transparent !important;
+      border-left-color: transparent !important;
+      -webkit-transform: rotate(45deg);
+      transform: rotate(45deg);
+      margin-top: -6px;
+    }
+  }
+
+  .style4 {
+    .style4-border1 {
+      width: 160px;
+      height: 2px;
+    }
+
+    .style4-border2 {
+      width: 260px;
+      height: 1px;
+    }
+  }
+
+  .style5 {
+    .style5-box {
+      width: 10px;
+      height: 10px;
+      border: 1px solid #000;
+      display: inline-block;
+      -webkit-transform: rotate(45deg);
+      transform: rotate(45deg);
+      margin: 0 10px;
+    }
+
+    .style5-border {
+      width: 160px;
+      height: 1px;
+    }
+  }
+
+  .style6 {
+    .style6-bos {
+      border: 1px solid #ccc;
+      padding: 4px 4px;
+      position: relative;
+
+      .style6-box {
+        border: 1px solid #ccc;
+        padding: 2px 14px;
+      }
+
+      .style6-border {
+        width: 50px;
+        height: 4px;
+        position: absolute;
+        top: 50%;
+
+        &.style6-border1 {
+          left: -40px;
+        }
+
+        &.style6-border2 {
+          right: -40px;
+        }
+      }
+    }
+  }
+
+  .style7 {
+    .style7-bos {
+      position: relative;
+      margin-bottom: 6px;
+
+      .style7-text {
+        padding: 2px 14px;
+        position: relative;
+        z-index: 2;
+        background-color: #ffffff;
+        border: 1px solid #ccc;
+      }
+
+      .style7-line {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        border: 1px solid #ccc;
+        top: 6px;
+        left: 6px;
+        z-index: 0;
+      }
+    }
+  }
+
+  .style8 {
+    .style8-bos {
+      position: relative;
+      margin-bottom: 6px;
+
+      .style8-text {
+        padding: 2px 14px;
+        position: relative;
+        z-index: 2;
+        color: #ffffff !important;
+      }
+
+      .style8-line {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        border: 1px solid #ccc;
+        top: 6px;
+        left: 6px;
+        z-index: 0;
+      }
+    }
+  }
+
+  .style9 {
+    position: relative;
+
+    .style9-border {
+      height: 80%;
+      width: 3px;
+      position: absolute;
+    }
+  }
+
+  .style10 {
+    .style10-bos {
+      height: 100%;
+      position: relative;
+
+      img {
+        height: 100%;
+        position: absolute;
+
+        &.style10-img1 {
+          left: -70%;
+        }
+
+        &.style10-img2 {
+          right: -70%;
+        }
+      }
+    }
+  }
+
+  .style11 {
+    .style11-bos {
+      height: 100%;
+      position: relative;
+
+      .style11-img {
+        height: 100%;
+        position: absolute;
+
+        &.style11-img1 {
+          left: -60%;
+        }
+
+        &.style11-img2 {
+          right: -60%;
+        }
+      }
+
+      .style11-text {
+        position: relative;
+        z-index: 2;
+      }
+
+      .style11-img3 {
+        position: absolute;
+        width: 120%;
+        bottom: 0px;
+        left: -10%;
+      }
+    }
+  }
+
+  .style13 {
+    .style13-bos {
+      height: 100%;
+      position: relative;
+
+      img {
+        height: 100%;
+        position: absolute;
+
+        &.style13-img1 {
+          left: -80%;
+        }
+
+        &.style13-img2 {
+          right: -80%;
+        }
+      }
+    }
+  }
+}
+
+.textTitle-pages {
+  width: 100%;
+
+  .textTitle-bos {
+    background-color: #ffffff;
+    line-height: 45px;
+    padding-left: 20px;
+    font-size: 18px;
+    color: #333333;
+    font-weight: bold;
+  }
+}
+</style>

Разница между файлами не показана из-за своего большого размера
+ 2 - 0
src/views/home/theme.vue


+ 25 - 15
src/views/item/index.vue

@@ -20,7 +20,7 @@
         <div class="head-right flex-column-between">
         <div class="head-right flex-column-between">
           <div>
           <div>
             <div class="right-title">{{ dataInfo.itemName || '' }}</div>
             <div class="right-title">{{ dataInfo.itemName || '' }}</div>
-            <div class="right-num">商品库存 {{ dataInfo.stock || 0 }}套</div>
+            <div class="right-num">商品库存 {{ dataInfo.allStock || 0 }}套</div>
             <div class="right-price flex-row-between">
             <div class="right-price flex-row-between">
               <div class="flex-row-start">
               <div class="flex-row-start">
                 <div class="price1">
                 <div class="price1">
@@ -81,14 +81,14 @@
             <div class="number-bos">
             <div class="number-bos">
               <div>数量</div>
               <div>数量</div>
               <div class="flex-row-start number-box">
               <div class="flex-row-start number-box">
-                <el-input-number v-model="num" :min="1" :max="10" @change="handleChange" />
-                <div style="margin-left: 10px">本产品限购2件</div>
+                <el-input-number v-model="num" :min="1" :max="dataInfo.allStock" @change="handleChange" />
+                <div style="margin-left: 10px">提示:本产品起订为:{{ dataInfo.minOrderQuantity }}台</div>
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>
           <div class="bnt-bos flex-row-start">
           <div class="bnt-bos flex-row-start">
-            <div @click="onCart">加入购物车</div>
-            <!-- <div>立即购买</div> -->
+            <el-button :disabled="dataInfo.allStock > 0 ? false : true" class="btn" type="primary" @click="onCart">加入购物车</el-button>
+            <span v-if="dataInfo.allStock <= 0" class="btn-text">(库存不足)</span>
           </div>
           </div>
         </div>
         </div>
       </el-affix>
       </el-affix>
@@ -245,6 +245,7 @@ const getInfo = () => {
         }
         }
       }
       }
       dataInfo.value = res.data;
       dataInfo.value = res.data;
+      dataInfo.value.allStock = Number(res.data.totalInventory || 0) + Number(res.data.nowInventory || 0) + Number(res.data.virtualInventory || 0);
     }
     }
   });
   });
 };
 };
@@ -307,7 +308,14 @@ const onCarousel = (type: number, index?: any) => {
 };
 };
 
 
 const handleChange = (val: any) => {
 const handleChange = (val: any) => {
-  // num.value = val;
+  const numberVal = Number(val);
+  const step = dataInfo.value.minOrderQuantity || 1;
+  num.value = Math.floor(numberVal / step) * step;
+  // if (val > num.value) {
+  //   num.value = Math.ceil(numberVal / step) * step;
+  // } else {
+  //   num.value = Math.floor(numberVal / step) * step;
+  // }
 };
 };
 import { cartStore } from '@/store/modules/cart';
 import { cartStore } from '@/store/modules/cart';
 const cart = cartStore();
 const cart = cartStore();
@@ -495,22 +503,24 @@ getRecommendedCategoryProductList({}).then((res) => {
       }
       }
 
 
       .bnt-bos {
       .bnt-bos {
-        width: 428px;
+        width: 100%;
         height: 44px;
         height: 44px;
-        border-radius: 10px;
         overflow: hidden;
         overflow: hidden;
+        .btn-text {
+          font-size: 12px;
+          color: #666666;
+          margin-left: 10px;
+        }
 
 
-        div {
-          width: 428px;
-          // width: 214px;
+        .btn {
+          flex: 1;
           height: 44px;
           height: 44px;
           line-height: 44px;
           line-height: 44px;
-          text-align: center;
-          cursor: pointer;
+          max-width: 428px;
 
 
           &:nth-of-type(1) {
           &:nth-of-type(1) {
-            background: #fcecf1;
-            color: #e7000b;
+            // background: #fcecf1;
+            // color: #e7000b;
           }
           }
 
 
           &:nth-of-type(2) {
           &:nth-of-type(2) {

+ 10 - 1
src/views/payc/index.vue

@@ -36,7 +36,7 @@
     </div>
     </div>
     <div class="pay-foot">
     <div class="pay-foot">
       <div class="foot-bos">
       <div class="foot-bos">
-        <el-button class="bnt1">返回购物车修改</el-button>
+        <el-button class="bnt1" @click="handleCancelOrder">取消订单</el-button>
         <el-button class="bnt2" type="primary" @click="onSubmit">提交订单</el-button>
         <el-button class="bnt2" type="primary" @click="onSubmit">提交订单</el-button>
       </div>
       </div>
     </div>
     </div>
@@ -74,6 +74,15 @@ const onSubmit = () => {
     }
     }
   });
   });
 };
 };
+
+import { cancelOrder } from '@/api/pc/enterprise/order';
+const handleCancelOrder = () => {
+  cancelOrder({ id: orderId.value, orderStatus: '7' }).then((res) => {
+    if (res.code == 200) {
+      onPath('/cart');
+    }
+  });
+};
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>

+ 5 - 21
src/views/search/brand.vue

@@ -39,9 +39,10 @@
     </div>
     </div>
     <!-- 商品 -->
     <!-- 商品 -->
     <div class="expert-bos">
     <div class="expert-bos">
-      <div v-for="(item, index) in dataList" :key="index" class="expert-list" @click="onPath('/item?id=' + item.id)">
+      <!-- @click="onPath('/item?id=' + item.id)" -->
+      <div v-for="(item, index) in dataList" :key="index" class="expert-list">
         <img :src="item.brandBigImage" alt="" />
         <img :src="item.brandBigImage" alt="" />
-        <div class="itemName ellipsis">{{ item.brandRegistrant || 'dffddsfsdf' }}</div>
+        <div class="itemName ellipsis">{{ item.brandName || '' }}</div>
       </div>
       </div>
     </div>
     </div>
     <!-- 游标分页控制 -->
     <!-- 游标分页控制 -->
@@ -75,7 +76,7 @@ const httpObj = ref<any>({
   categoryId: '',
   categoryId: '',
   initial: '',
   initial: '',
   name: '',
   name: '',
-  pageSize: 10,
+  pageSize: 30,
   pageNum: 1
   pageNum: 1
 });
 });
 const initialList = ref<any>([
 const initialList = ref<any>([
@@ -112,28 +113,11 @@ const sortField2 = ref<any>('');
 const sortField3 = ref<any>('');
 const sortField3 = ref<any>('');
 
 
 const getList = () => {
 const getList = () => {
-  if (sortField1.value) {
-    httpObj.value.sortField = '1';
-    httpObj.value.sortOrder = sortField1.value;
-  }
-  if (sortField2.value) {
-    httpObj.value.sortField = httpObj.value.sortField + (httpObj.value.sortField ? ',2' : '2');
-    httpObj.value.sortOrder = httpObj.value.sortOrder + (httpObj.value.sortOrder ? ',' + sortField2.value : sortField2.value);
-  }
-  if (sortField3.value) {
-    httpObj.value.sortField = httpObj.value.sortField + (httpObj.value.sortField ? ',3' : '3');
-    httpObj.value.sortOrder = httpObj.value.sortOrder + (httpObj.value.sortOrder ? ',' + sortField3.value : sortField3.value);
-  }
-  if (checkList.value.length > 0) {
-    httpObj.value.isCustomize = 1;
-  } else {
-    httpObj.value.isCustomize = '';
-  }
   getBrandByCategoryList(httpObj.value).then((res) => {
   getBrandByCategoryList(httpObj.value).then((res) => {
     if (res.code == 200) {
     if (res.code == 200) {
       dataList.value = res.rows;
       dataList.value = res.rows;
       // 判断是否还有更多数据
       // 判断是否还有更多数据
-      hasMore.value = dataList.value.length === httpObj.value.pageSize;
+      hasMore.value = res.total > httpObj.value.pageSize * httpObj.value.pageNum;
     }
     }
   });
   });
 };
 };

+ 17 - 1
src/views/trad/index.vue

@@ -45,6 +45,7 @@
           v-model="form.deliveryDate"
           v-model="form.deliveryDate"
           type="date"
           type="date"
           placeholder="选择日期"
           placeholder="选择日期"
+          :disabled-date="disabledDate"
         />
         />
       </div>
       </div>
       <div class="form-bos">
       <div class="form-bos">
@@ -142,7 +143,7 @@
           <div class="flex-row-between" style="width: 100%">
           <div class="flex-row-between" style="width: 100%">
             <div></div>
             <div></div>
             <div class="bnt-bos">
             <div class="bnt-bos">
-              <el-button class="bnt1">返回购物车修改</el-button>
+              <el-button @click="onPath('/cart')" class="bnt1">返回购物车修改</el-button>
               <el-button @click="onSubmit" class="bnt2" type="primary">提交订单</el-button>
               <el-button @click="onSubmit" class="bnt2" type="primary">提交订单</el-button>
             </div>
             </div>
           </div>
           </div>
@@ -237,6 +238,11 @@ const loadAddressList = async () => {
       addressList.value = res.rows || [];
       addressList.value = res.rows || [];
       if (res.rows.length > 0) {
       if (res.rows.length > 0) {
         form.value.shippingAddressId = res.rows[0].id;
         form.value.shippingAddressId = res.rows[0].id;
+        addressList.value.forEach((item: any) => {
+          if (item.defaultAddress == 0) {
+            form.value.shippingAddressId = item.id;
+          }
+        });
       }
       }
     }
     }
   } catch (error) {
   } catch (error) {
@@ -355,6 +361,16 @@ const handleSave = async () => {
     ElMessage.error('操作失败');
     ElMessage.error('操作失败');
   }
   }
 };
 };
+
+const disabledDate = (date: Date) => {
+  // 获取今天的零点时间戳
+  const today = new Date();
+  today.setHours(0, 0, 0, 0);
+
+  // 如果传入的日期 < 今天,则禁用 (返回 true)
+  // 这样今天及以后的日期都会返回 false (可选)
+  return date.getTime() < today.getTime();
+};
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>

Некоторые файлы не были показаны из-за большого количества измененных файлов