Просмотр исходного кода

Merge branch 'master' of http://8.152.4.3:3000/yp_web/yoe-opm-web

hurx 3 дней назад
Родитель
Сommit
fc34855d94

+ 72 - 21
src/api/diy/index.ts

@@ -1,6 +1,6 @@
 import request from '@/utils/request';
 import request from '@/utils/request';
 
 
-// 自定义页面分页列表
+// H5自定义页面分页列表
 export function diyList(query: any) {
 export function diyList(query: any) {
   return request({
   return request({
     url: '/mall/diyPage/diy',
     url: '/mall/diyPage/diy',
@@ -17,25 +17,7 @@ export function delDiy(id: any) {
   });
   });
 }
 }
 
 
-// 自定义页面模版
-export function template(query: any) {
-  return request({
-    url: '/mall/diyPage/template',
-    method: 'get',
-    params: query
-  });
-}
-
-// 页面初始化数据
-export function diyInit(query: any) {
-  return request({
-    url: '/mall/diyPage/init',
-    method: 'get',
-    params: query
-  });
-}
-
-// 新增自定义页面
+// H5新增自定义页面
 export function addDiy(data: any) {
 export function addDiy(data: any) {
   return request({
   return request({
     url: '/mall/diyPage',
     url: '/mall/diyPage',
@@ -44,7 +26,7 @@ export function addDiy(data: any) {
   });
   });
 }
 }
 
 
-// 新增自定义页面
+// H5编辑自定义页面
 export function editDiy(data: any) {
 export function editDiy(data: any) {
   return request({
   return request({
     url: '/mall/diyPage',
     url: '/mall/diyPage',
@@ -53,6 +35,23 @@ export function editDiy(data: any) {
   });
   });
 }
 }
 
 
+// H5获取自定义页面详细信息
+export function LookDiy(id: any) {
+  return request({
+    url: '/mall/diyPage/' + id,
+    method: 'get'
+  });
+}
+
+// 页面初始化数据
+export function diyInit(query: any) {
+  return request({
+    url: '/mall/diyPage/init',
+    method: 'get',
+    params: query
+  });
+}
+
 // pc自定义页面分页列表
 // pc自定义页面分页列表
 export function pcDiyList(query: any) {
 export function pcDiyList(query: any) {
   return request({
   return request({
@@ -95,3 +94,55 @@ export function pcLookDiy(id: any) {
     method: 'get'
     method: 'get'
   });
   });
 }
 }
+
+// 查询mini装修页面模版列表
+export function miniList(query: any) {
+  return request({
+    url: '/mall/diyMiniTemplatePage/list',
+    method: 'get',
+    params: query
+  });
+}
+
+// 新增mini装修页面模版
+export function addMin(data: any) {
+  return request({
+    url: '/mall/diyMiniTemplatePage',
+    method: 'post',
+    data: data
+  });
+}
+
+// 修改mini装修页面模版
+export function editMin(data: any) {
+  return request({
+    url: '/mall/diyMiniTemplatePage',
+    method: 'put',
+    data: data
+  });
+}
+
+// 删除mini装修页面模版
+export function delMin(id: any) {
+  return request({
+    url: '/mall/diyMiniTemplatePage/' + id,
+    method: 'delete'
+  });
+}
+
+// 获取mini装修页面模版详细信息
+export function LookMin(id: any) {
+  return request({
+    url: '/mall/diyMiniTemplatePage/' + id,
+    method: 'get'
+  });
+}
+
+// 自定义页面模版
+export function template(query: any) {
+  return request({
+    url: '/mall/diyPage/template',
+    method: 'get',
+    params: query
+  });
+}

+ 5 - 0
src/router/index.ts

@@ -57,6 +57,11 @@ export const constantRoutes: RouteRecordRaw[] = [
     component: () => import('@/views/diy/edit.vue'),
     component: () => import('@/views/diy/edit.vue'),
     hidden: true
     hidden: true
   },
   },
+  {
+    path: '/diy/miniEdit',
+    component: () => import('@/views/diy/miniEdit.vue'),
+    hidden: true
+  },
   {
   {
     path: '/diy/pcdiy',
     path: '/diy/pcdiy',
     component: () => import('@/views/diy/pcdiy.vue'),
     component: () => import('@/views/diy/pcdiy.vue'),

+ 2 - 2
src/views/diy/components/edit-carousel-search.vue

@@ -55,7 +55,7 @@
             </div>
             </div>
           </el-form-item>
           </el-form-item>
           <el-form-item label="链接地址">
           <el-form-item label="链接地址">
-            <diy-link v-model="diyStore.editComponent.search.link" />
+            <WebLinkInput v-model="diyStore.editComponent.search.link" placeholder="请输入或选择链接" />
           </el-form-item>
           </el-form-item>
         </el-form>
         </el-form>
 
 
@@ -252,7 +252,7 @@
                 </div>
                 </div>
 
 
                 <el-form-item label="链接地址">
                 <el-form-item label="链接地址">
-                  <diy-link v-model="item.link" />
+                  <WebLinkInput v-model="item.link" placeholder="请输入或选择链接" />
                 </el-form-item>
                 </el-form-item>
               </div>
               </div>
             </div>
             </div>

+ 405 - 0
src/views/diy/components/edit-goods-list copy.vue

@@ -0,0 +1,405 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">风格选择</h3>
+        <div class="flex items-center mb-[18px] rounded overflow-hidden">
+          <span
+            class="iconfont iconzuoyoutuwenpc border-[1px] border-solid border-[#eee] cursor-pointer flex-1 flex items-center justify-center py-[5px]"
+            :class="{ 'border-[var(--el-color-primary)] text-[var(--el-color-primary)]': diyStore.editComponent.style == 'style-1' }"
+            @click="styleChangeFn('style-1')"
+          ></span>
+
+          <span
+            class="iconfont iconshangxiatuwenpc border-[1px] border-solid border-[#eee] cursor-pointer flex-1 flex items-center justify-center py-[5px]"
+            :class="{ 'border-[var(--el-color-primary)] text-[var(--el-color-primary)]': diyStore.editComponent.style == 'style-2' }"
+            @click="styleChangeFn('style-2')"
+          ></span>
+          <span
+            class="iconfont iconliebiaopc border-[1px] border-solid border-[#eee] cursor-pointer flex-1 flex items-center justify-center py-[5px]"
+            :class="{ 'border-[var(--el-color-primary)] text-[var(--el-color-primary)]': diyStore.editComponent.style == 'style-3' }"
+            @click="styleChangeFn('style-3')"
+          ></span>
+        </div>
+      </div>
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">选择数据源</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="排序">
+            <el-radio-group v-model="diyStore.editComponent.sortWay">
+              <el-radio value="default">综合</el-radio>
+              <el-radio value="sale_num">销量</el-radio>
+              <el-radio value="price">价格</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="选择商品">
+            <el-radio-group v-model="diyStore.editComponent.source" title="选择商品">
+              <el-radio :value="1">指定商品</el-radio>
+              <el-radio :value="2">商品分类</el-radio>
+              <el-radio :value="3">商品品牌</el-radio>
+              <!-- <el-radio value="all">全部商品</el-radio>
+              <el-radio value="category">选择分类</el-radio>
+              <el-radio value="custom">手动选择</el-radio> -->
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="指定商品" v-if="diyStore.editComponent.source == 1">
+            <div class="data-num" @click="openDialog">
+              <!-- <span v-if="diyStore.editComponent.goodsIds.length == 0">请选择</span>
+              <span v-else>已选择{{ diyStore.editComponent.goodsIds.length }}个</span> -->
+              <el-icon><ArrowRight /></el-icon>
+            </div>
+          </el-form-item>
+          <el-form-item label="选择分类" v-if="diyStore.editComponent.source == 'category'">
+            <div class="flex items-center w-full">
+              <div class="cursor-pointer ml-auto" @click="categoryShowDialogOpen">
+                <span class="text-[var(--el-color-primary)]">{{ diyStore.editComponent.goods_category_name }}</span>
+                <span class="iconfont iconxiangyoujiantou"></span>
+              </div>
+            </div>
+          </el-form-item>
+          <el-form-item label="商品数量" v-if="diyStore.editComponent.source == 'all' || diyStore.editComponent.source == 'category'">
+            <el-slider class="goods-list-slider" show-input v-model="diyStore.editComponent.num" :min="1" :max="20" size="small" />
+          </el-form-item>
+          <!-- <el-form-item label="手动选择" v-if="diyStore.editComponent.source == 'custom'">
+            <goods-select-popup ref="goodsSelectPopupRef" v-model="diyStore.editComponent.goods_ids" :min="1" :max="99" />
+          </el-form-item> -->
+        </el-form>
+
+        <el-dialog v-model="categoryShowDialog" title="商品分类" width="750px" :destroy-on-close="true" :close-on-click-modal="false">
+          <el-table
+            :data="categoryTable.data"
+            ref="categoryTableRef"
+            size="large"
+            v-loading="categoryTable.loading"
+            height="450px"
+            @selection-change="handleSelectionChange"
+            row-key="category_id"
+            :expand-row-keys="expand_category_ids"
+            :tree-props="{ hasChildren: 'hasChildren', children: 'child_list' }"
+          >
+            <template #empty>
+              <span>{{ !categoryTable.loading ? '还没有安装应用' : '' }}</span>
+            </template>
+            <el-table-column type="selection" width="55" />
+            <el-table-column label="分类名称" min-width="120">
+              <template #default="{ row }">
+                <span class="order-2">{{ row.category_name }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="分类图片" width="170" align="left">
+              <template #default="{ row }">
+                <div class="h-[30px]">
+                  <el-image class="w-[30px] h-[30px]" :src="img(row.image)" fit="contain">
+                    <template #error>
+                      <div class="image-slot">
+                        <!-- <img class="w-[30px] h-[30px]" src="@/addon/shop/assets/category_default.png" /> -->
+                      </div>
+                    </template>
+                  </el-image>
+                </div>
+              </template>
+            </el-table-column>
+          </el-table>
+          <div class="flex items-center justify-end mt-[15px]">
+            <el-button type="primary" @click="saveCategoryId">确认</el-button>
+            <el-button @click="categoryShowDialog = false">取消</el-button>
+          </div>
+        </el-dialog>
+      </div>
+
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">购买按钮</h3>
+        <el-form label-width="90px" class="px-[10px]">
+          <el-form-item label="是否显示">
+            <el-switch v-model="diyStore.editComponent.btnStyle.control" />
+          </el-form-item>
+          <el-form-item label="点击事件" v-if="diyStore.editComponent.btnStyle.control">
+            <el-radio-group v-model="diyStore.editComponent.btnStyle.cartEvent">
+              <el-radio value="detail">商品详情</el-radio>
+              <el-radio v-if="diyStore.editComponent.style != 'style-3'" value="cart">加入购物车</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="样式" class="!items-center" v-if="diyStore.editComponent.btnStyle.control">
+            <div class="flex">
+              <template v-for="(item, index) in btnStyleList" :key="index">
+                <div
+                  v-if="item.isShow == true"
+                  class="cursor-pointer flex items-center justify-center border-[1px] border-solid border-transparent rounded-[6px] py-[5px] px-[8px] mr-[10px]"
+                  :class="{ '!border-[var(--el-color-primary)]': diyStore.editComponent.btnStyle.style == item.value }"
+                >
+                  <div
+                    v-if="item.type == 'icon'"
+                    :class="['nc-iconfont !text-[25px] text-[var(--el-color-primary)]', item.title]"
+                    @click="changeBtnStyle(item)"
+                  ></div>
+                  <div
+                    v-if="item.type == 'button'"
+                    class="leading-[1] text-[12px] px-[10px] py-[8px] text-[#fff] rounded-[20px] bg-[var(--el-color-primary)]"
+                    @click="changeBtnStyle(item)"
+                  >
+                    {{ item.title }}
+                  </div>
+                </div>
+              </template>
+            </div>
+          </el-form-item>
+          <el-form-item label="文本" v-if="diyStore.editComponent.btnStyle.control && diyStore.editComponent.btnStyle.style == 'button'">
+            <el-input v-model.trim="diyStore.editComponent.btnStyle.text" placeholder="请输入按钮文字" clearable maxlength="4" show-word-limit />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">显示内容</h3>
+        <el-form label-width="90px" class="px-[10px]">
+          <el-form-item label="商品名称" v-if="diyStore.editComponent.goodsNameStyle.isShow">
+            <el-switch v-model="diyStore.editComponent.goodsNameStyle.control" />
+          </el-form-item>
+          <el-form-item label="销售价" v-if="diyStore.editComponent.priceStyle.isShow">
+            <el-switch v-model="diyStore.editComponent.priceStyle.control" />
+          </el-form-item>
+          <el-form-item label="商品销量" v-if="diyStore.editComponent.saleStyle.isShow">
+            <el-switch v-model="diyStore.editComponent.saleStyle.control" />
+          </el-form-item>
+          <el-form-item label="商品标签" v-if="diyStore.editComponent.labelStyle.isShow">
+            <el-switch v-model="diyStore.editComponent.labelStyle.control" />
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">商品样式</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="商品背景">
+            <el-color-picker v-model="diyStore.editComponent.elementBgColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="商品名称">
+            <el-color-picker v-model="diyStore.editComponent.goodsNameStyle.color" show-alpha :predefine="diyStore.predefineColors" />
+            <div class="mr-[20px]"></div>
+            <el-radio-group v-model="diyStore.editComponent.goodsNameStyle.fontWeight">
+              <el-radio :value="'normal'">常规</el-radio>
+              <el-radio :value="'bold'">加粗</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="图片圆角">
+            <el-slider v-model="diyStore.editComponent.imgElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
+          </el-form-item>
+          <el-form-item label="销售价">
+            <el-color-picker v-model="diyStore.editComponent.priceStyle.color" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="商品销量">
+            <el-color-picker v-model="diyStore.editComponent.saleStyle.color" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="上圆角">
+            <el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
+          </el-form-item>
+          <el-form-item label="下圆角">
+            <el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div class="edit-attr-item-wrap" v-if="diyStore.editComponent.btnStyle.control">
+        <h3 class="mb-[10px]">购买按钮</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="是否加粗" v-if="diyStore.editComponent.btnStyle.style == 'button'">
+            <el-switch v-model="diyStore.editComponent.btnStyle.fontWeight" />
+          </el-form-item>
+          <el-form-item label="文字颜色">
+            <el-color-picker v-model="diyStore.editComponent.btnStyle.textColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="背景颜色">
+            <el-color-picker v-model="diyStore.editComponent.btnStyle.startBgColor" show-alpha :predefine="diyStore.predefineColors" />
+            <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
+            <el-color-picker v-model="diyStore.editComponent.btnStyle.endBgColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="圆角" v-if="diyStore.editComponent.btnStyle.style == 'button'">
+            <el-slider v-model="diyStore.editComponent.btnStyle.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+
+    <goods-dialog ref="goodsDialogRef" :categoryOptions="categoryOptions"></goods-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+// import { getCategoryTree } from '@/addon/shop/api/goods';
+import { img } from '@/utils/common';
+import useDiyStore from '@/store/modules/diy';
+import { ElTable } from 'element-plus';
+// import goodsSelectPopup from '@/addon/shop/views/goods/components/goods-select-popup.vue';
+const categoryOptions = ref<any>([]);
+const goodsDialogRef = ref<any>(null);
+
+const diyStore: any = useDiyStore();
+diyStore.editComponent.ignore = []; // 忽略公共属性
+
+// 组件验证
+diyStore.editComponent.verify = (index: number) => {
+  const res = { code: true, message: '' };
+
+  if (diyStore.value[index].source == 'category') {
+    if (diyStore.value[index].goods_category == '') {
+      res.code = false;
+      res.message = '请选择商品分类';
+    }
+  } else if (diyStore.value[index].source == 'custom') {
+    if (diyStore.value[index].goods_ids.length == 0) {
+      res.code = false;
+      res.message = '请选择商品';
+    }
+  }
+  return res;
+};
+
+const categoryShowDialog = ref(false);
+
+const categoryTable = reactive({
+  loading: true,
+  data: []
+});
+onMounted(() => {
+  loadCategoryList();
+  btnStyleList.forEach((item, index, arr) => {
+    if (item.type == 'button') {
+      if (diyStore.editComponent.style == 'style-3') {
+        item.isShow = false;
+      } else {
+        item.isShow = true;
+      }
+    }
+  });
+});
+
+const styleChangeFn = (style) => {
+  btnStyleList.forEach((item, index, arr) => {
+    if (item.type == 'button') {
+      if (style == 'style-3') {
+        item.isShow = false;
+      } else {
+        item.isShow = true;
+      }
+    }
+  });
+
+  if (style == 'style-3') {
+    diyStore.editComponent.btnStyle.style = btnStyleList[1].value;
+    diyStore.editComponent.btnStyle.cartEvent = 'detail';
+
+    diyStore.editComponent.saleStyle.isShow = false;
+    diyStore.editComponent.labelStyle.isShow = false;
+  } else {
+    diyStore.editComponent.btnStyle.style = btnStyleList[0].value;
+
+    diyStore.editComponent.saleStyle.isShow = true;
+    diyStore.editComponent.labelStyle.isShow = true;
+  }
+  diyStore.editComponent.style = style;
+};
+
+const btnStyleList = reactive([
+  {
+    isShow: true,
+    type: 'button',
+    title: diyStore.editComponent.btnStyle.text,
+    value: 'button'
+  },
+  {
+    isShow: true,
+    type: 'icon',
+    title: 'nc-icon-jiahaoV6xx',
+    value: 'nc-icon-jiahaoV6xx'
+  },
+  {
+    isShow: true,
+    type: 'icon',
+    title: 'nc-icon-gouwuche1',
+    value: 'nc-icon-gouwuche1'
+  }
+]);
+
+const changeBtnStyle = (item: any) => {
+  diyStore.editComponent.btnStyle.style = item.value;
+};
+
+const categoryTableRef = ref<InstanceType<typeof ElTable>>();
+/**
+ * 获取商品分类列表
+ */
+let currCategoryData: any = null;
+const loadCategoryList = () => {
+  categoryTable.loading = true;
+
+  // getCategoryTree()
+  //   .then((res) => {
+  //     categoryTable.loading = false;
+  //     categoryTable.data = res.data;
+  //   })
+  //   .catch(() => {
+  //     categoryTable.loading = false;
+  //   });
+};
+
+// 选择商品分类
+const handleSelectionChange = (val: string | any[]) => {
+  let data = '';
+  if (val) data = val[val.length - 1];
+  if (val.length > 1) categoryTableRef.value!.clearSelection();
+  if (data) categoryTableRef.value!.toggleRowSelection(data, true);
+  currCategoryData = data;
+};
+
+const saveCategoryId = () => {
+  diyStore.editComponent.goods_category = currCategoryData.category_id;
+  diyStore.editComponent.goods_category_name = currCategoryData.category_name;
+  categoryShowDialog.value = false;
+};
+
+const categoryShowDialogOpen = () => {
+  categoryShowDialog.value = true;
+  nextTick(() => {
+    setRowSelection();
+  });
+};
+
+// 分类数据选中回填,设置展开行
+const expand_category_ids = ref<Array<any>>([]);
+const setRowSelection = () => {
+  expand_category_ids.value = [];
+  categoryTable.data.forEach((el: any) => {
+    if (diyStore.editComponent.goods_category == el.category_id) {
+      categoryTableRef.value!.toggleRowSelection(el, true);
+    } else if (el.child_list && el.child_list.length) {
+      el.child_list.forEach((v: any) => {
+        if (diyStore.editComponent.goods_category == v.category_id) {
+          expand_category_ids.value.push(el.category_id.toString());
+          categoryTableRef.value!.toggleRowSelection(v, true);
+        }
+      });
+    }
+  });
+};
+
+//打开弹窗
+const openDialog = () => {
+  goodsDialogRef.value.onOpen();
+};
+
+defineExpose({});
+</script>
+<style lang="scss">
+.goods-list-slider {
+  .el-slider__input {
+    width: 100px;
+  }
+}
+</style>

+ 40 - 12
src/views/diy/components/edit-goods-list.vue

@@ -28,18 +28,28 @@
         <el-form label-width="80px" class="px-[10px]">
         <el-form label-width="80px" class="px-[10px]">
           <el-form-item label="排序">
           <el-form-item label="排序">
             <el-radio-group v-model="diyStore.editComponent.sortWay">
             <el-radio-group v-model="diyStore.editComponent.sortWay">
-              <el-radio label="default">综合</el-radio>
-              <el-radio label="sale_num">销量</el-radio>
-              <el-radio label="price">价格</el-radio>
+              <el-radio value="default">综合</el-radio>
+              <el-radio value="sale_num">销量</el-radio>
+              <el-radio value="price">价格</el-radio>
             </el-radio-group>
             </el-radio-group>
           </el-form-item>
           </el-form-item>
           <el-form-item label="选择商品">
           <el-form-item label="选择商品">
             <el-radio-group v-model="diyStore.editComponent.source" title="选择商品">
             <el-radio-group v-model="diyStore.editComponent.source" title="选择商品">
-              <el-radio label="all">全部商品</el-radio>
-              <el-radio label="category">选择分类</el-radio>
-              <el-radio label="custom">手动选择</el-radio>
+              <el-radio :value="1">指定商品</el-radio>
+              <el-radio :value="2">商品分类</el-radio>
+              <el-radio :value="3">商品品牌</el-radio>
+              <!-- <el-radio value="all">全部商品</el-radio>
+              <el-radio value="category">选择分类</el-radio>
+              <el-radio value="custom">手动选择</el-radio> -->
             </el-radio-group>
             </el-radio-group>
           </el-form-item>
           </el-form-item>
+          <el-form-item label="指定商品" v-if="diyStore.editComponent.source == 1">
+            <div class="data-num" @click="openDialog">
+              <span v-if="diyStore.editComponent.goodsIds.length == 0">请选择</span>
+              <span v-else>已选择{{ diyStore.editComponent.goodsIds.length }}个</span>
+              <el-icon><ArrowRight /></el-icon>
+            </div>
+          </el-form-item>
           <el-form-item label="选择分类" v-if="diyStore.editComponent.source == 'category'">
           <el-form-item label="选择分类" v-if="diyStore.editComponent.source == 'category'">
             <div class="flex items-center w-full">
             <div class="flex items-center w-full">
               <div class="cursor-pointer ml-auto" @click="categoryShowDialogOpen">
               <div class="cursor-pointer ml-auto" @click="categoryShowDialogOpen">
@@ -51,9 +61,9 @@
           <el-form-item label="商品数量" v-if="diyStore.editComponent.source == 'all' || diyStore.editComponent.source == 'category'">
           <el-form-item label="商品数量" v-if="diyStore.editComponent.source == 'all' || diyStore.editComponent.source == 'category'">
             <el-slider class="goods-list-slider" show-input v-model="diyStore.editComponent.num" :min="1" :max="20" size="small" />
             <el-slider class="goods-list-slider" show-input v-model="diyStore.editComponent.num" :min="1" :max="20" size="small" />
           </el-form-item>
           </el-form-item>
-          <el-form-item label="手动选择" v-if="diyStore.editComponent.source == 'custom'">
+          <!-- <el-form-item label="手动选择" v-if="diyStore.editComponent.source == 'custom'">
             <goods-select-popup ref="goodsSelectPopupRef" v-model="diyStore.editComponent.goods_ids" :min="1" :max="99" />
             <goods-select-popup ref="goodsSelectPopupRef" v-model="diyStore.editComponent.goods_ids" :min="1" :max="99" />
-          </el-form-item>
+          </el-form-item> -->
         </el-form>
         </el-form>
 
 
         <el-dialog v-model="categoryShowDialog" title="商品分类" width="750px" :destroy-on-close="true" :close-on-click-modal="false">
         <el-dialog v-model="categoryShowDialog" title="商品分类" width="750px" :destroy-on-close="true" :close-on-click-modal="false">
@@ -106,8 +116,8 @@
           </el-form-item>
           </el-form-item>
           <el-form-item label="点击事件" v-if="diyStore.editComponent.btnStyle.control">
           <el-form-item label="点击事件" v-if="diyStore.editComponent.btnStyle.control">
             <el-radio-group v-model="diyStore.editComponent.btnStyle.cartEvent">
             <el-radio-group v-model="diyStore.editComponent.btnStyle.cartEvent">
-              <el-radio label="detail">商品详情</el-radio>
-              <el-radio v-if="diyStore.editComponent.style != 'style-3'" label="cart">加入购物车</el-radio>
+              <el-radio value="detail">商品详情</el-radio>
+              <el-radio v-if="diyStore.editComponent.style != 'style-3'" value="cart">加入购物车</el-radio>
             </el-radio-group>
             </el-radio-group>
           </el-form-item>
           </el-form-item>
           <el-form-item label="样式" class="!items-center" v-if="diyStore.editComponent.btnStyle.control">
           <el-form-item label="样式" class="!items-center" v-if="diyStore.editComponent.btnStyle.control">
@@ -171,8 +181,8 @@
             <el-color-picker v-model="diyStore.editComponent.goodsNameStyle.color" show-alpha :predefine="diyStore.predefineColors" />
             <el-color-picker v-model="diyStore.editComponent.goodsNameStyle.color" show-alpha :predefine="diyStore.predefineColors" />
             <div class="mr-[20px]"></div>
             <div class="mr-[20px]"></div>
             <el-radio-group v-model="diyStore.editComponent.goodsNameStyle.fontWeight">
             <el-radio-group v-model="diyStore.editComponent.goodsNameStyle.fontWeight">
-              <el-radio :label="'normal'">常规</el-radio>
-              <el-radio :label="'bold'">加粗</el-radio>
+              <el-radio :value="'normal'">常规</el-radio>
+              <el-radio :value="'bold'">加粗</el-radio>
             </el-radio-group>
             </el-radio-group>
           </el-form-item>
           </el-form-item>
           <el-form-item label="图片圆角">
           <el-form-item label="图片圆角">
@@ -216,6 +226,8 @@
       <!-- 组件样式 -->
       <!-- 组件样式 -->
       <slot name="style"></slot>
       <slot name="style"></slot>
     </div>
     </div>
+
+    <goods-dialog ref="goodsDialogRef" :categoryOptions="categoryOptions"></goods-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
@@ -225,6 +237,8 @@ import { img } from '@/utils/common';
 import useDiyStore from '@/store/modules/diy';
 import useDiyStore from '@/store/modules/diy';
 import { ElTable } from 'element-plus';
 import { ElTable } from 'element-plus';
 // import goodsSelectPopup from '@/addon/shop/views/goods/components/goods-select-popup.vue';
 // import goodsSelectPopup from '@/addon/shop/views/goods/components/goods-select-popup.vue';
+const categoryOptions = ref<any>([]);
+const goodsDialogRef = ref<any>(null);
 
 
 const diyStore: any = useDiyStore();
 const diyStore: any = useDiyStore();
 diyStore.editComponent.ignore = []; // 忽略公共属性
 diyStore.editComponent.ignore = []; // 忽略公共属性
@@ -375,6 +389,11 @@ const setRowSelection = () => {
   });
   });
 };
 };
 
 
+//打开弹窗
+const openDialog = () => {
+  goodsDialogRef.value.onOpen();
+};
+
 defineExpose({});
 defineExpose({});
 </script>
 </script>
 <style lang="scss">
 <style lang="scss">
@@ -383,4 +402,13 @@ defineExpose({});
     width: 100px;
     width: 100px;
   }
   }
 }
 }
+.data-num {
+  width: 100%;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  color: var(--el-color-primary);
+  cursor: pointer;
+}
 </style>
 </style>

+ 1 - 1
src/views/diy/components/edit-graphic-nav.vue

@@ -74,7 +74,7 @@
               </div>
               </div>
 
 
               <el-form-item label="链接地址">
               <el-form-item label="链接地址">
-                <diy-link v-model="item.link" />
+                <WebLinkInput v-model="item.link" placeholder="请输入或选择链接" />
               </el-form-item>
               </el-form-item>
             </div>
             </div>
           </div>
           </div>

+ 40 - 0
src/views/diy/components/edit-shop-goods-detail-attr.vue

@@ -0,0 +1,40 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="是否显示">
+            <el-radio-group v-model="diyStore.editComponent.isShow">
+              <el-radio :value="true">显示</el-radio>
+              <el-radio :value="false">隐藏</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import useDiyStore from '@/store/modules/diy';
+
+const diyStore: any = useDiyStore();
+diyStore.editComponent.ignore = []; // 忽略公共属性
+
+// 组件验证
+diyStore.editComponent.verify = (index: number) => {
+  const res = { code: true, message: '' };
+  return res;
+};
+
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>

+ 229 - 245
src/views/diy/components/edit-shop-goods-detail-basic-info.vue

@@ -1,254 +1,238 @@
 <template>
 <template>
-  <!-- 内容 -->
-  <div class="content-wrap goods-detail-basic-info" v-show="diyStore.editTab == 'content'">
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">顶部导航</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="菜单内容">
-          <el-checkbox-group v-model="menuContent" :min="2" @change="menuContentChange">
-            <el-checkbox label="首页" value="index" />
-            <el-checkbox label="搜索" value="search" />
-            <el-checkbox label="购物车" value="cart" />
-            <el-checkbox label="个人中心" value="member" />
-            <el-checkbox label="我的收藏" value="collect" />
-            <el-checkbox label="商品列表" value="goods_list" />
-            <el-checkbox label="商品分类" value="goods_category" />
-          </el-checkbox-group>
-          <div class="text-sm text-gray-400">菜单内容最少选择2个</div>
-        </el-form-item>
-      </el-form>
-    </div>
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">商品媒体</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="商品主图">
-          <el-radio-group v-model="diyStore.editComponent.medium.type">
-            <el-radio label="square_img">固定方图</el-radio>
-            <el-radio label="height_adaptive">高度自适应</el-radio>
-            <div class="text-sm text-gray-400 leading-[1.6]">注意:高度自适应指商品主图的高度与第一张商品图的高度保持一致</div>
-          </el-radio-group>
-        </el-form-item>
-        <el-form-item label="轮播点">
-          <el-radio-group v-model="diyStore.editComponent.medium.indicator">
-            <el-radio :label="true">显示</el-radio>
-            <el-radio :label="false">隐藏</el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
-    </div>
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">价格展示</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="展示方式">
-          <el-radio-group v-model="diyStore.editComponent.priceRegion.showWay">
-            <el-radio label="normal">常规</el-radio>
-            <el-radio label="fixed">置顶</el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
-    </div>
-    <div class="edit-attr-item-wrap" v-if="diyStore.editComponent.priceRegion.showWay == 'fixed'">
-      <h3 class="mb-[10px]">普通价格背景图</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="风格选择" class="flex">
-          <span class="text-primary flex-1 cursor-pointer" @click="showGoodsStyle">{{ diyStore.editComponent.priceRegion.goodsStyle.title }}</span>
-          <el-icon>
-            <ArrowRight />
-          </el-icon>
-        </el-form-item>
-        <el-form-item label="背景图片">
-          <upload-image v-model="diyStore.editComponent.priceRegion.bgImg" :limit="1" />
-          <div class="text-sm text-gray-400">背景图片推荐尺寸:750*148</div>
-        </el-form-item>
-      </el-form>
-    </div>
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">活动价格背景图</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <div class="text-sm text-gray-400 mb-[10px]">适用场景:限时折扣、新人专享、会员价</div>
-        <el-form-item label="风格选择" class="flex">
-          <span class="text-primary flex-1 cursor-pointer" @click="showMarketingStyle">{{
-            diyStore.editComponent.priceRegion.marketingStyle.title
-          }}</span>
-          <el-icon>
-            <ArrowRight />
-          </el-icon>
-        </el-form-item>
-        <el-form-item label="背景图片">
-          <upload-image v-model="diyStore.editComponent.priceRegion.marketingBgImg" :limit="1" />
-          <div class="text-sm text-gray-400">背景图片推荐尺寸:750*148</div>
-        </el-form-item>
-      </el-form>
-    </div>
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">销售信息</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="是否展示">
-          <el-checkbox-group v-model="saleInfo" @change="saleInfoChange">
-            <el-checkbox label="划线价" value="underlined_price" />
-            <el-checkbox label="累计销量" value="sales" />
-            <el-checkbox label="库存" value="stock" />
-          </el-checkbox-group>
-        </el-form-item>
-      </el-form>
-    </div>
-    <!-- 普通商品风格 -->
-    <el-dialog v-model="goodsStyleDialog" title="selectStyle" width="460px">
-      <div class="flex flex-wrap">
-        <template v-for="(item, index) in Object.values(goodsStyleList)" :key="index">
-          <div
-            :class="{ 'border-primary': selectGoodsStyle.value == item.value }"
-            @click="changeGoodsStyle(item)"
-            class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]"
-          >
-            <img :src="img(item.url)" />
-          </div>
-        </template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap goods-detail-basic-info" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">顶部导航</h3>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="菜单内容">
+            <el-checkbox-group v-model="menuContent" :min="2" @change="menuContentChange">
+              <el-checkbox label="首页" value="index" />
+              <el-checkbox label="搜索" value="search" />
+              <el-checkbox label="购物车" value="cart" />
+              <el-checkbox label="个人中心" value="member" />
+              <el-checkbox label="我的收藏" value="collect" />
+              <el-checkbox label="商品列表" value="goods_list" />
+              <el-checkbox label="商品分类" value="goods_category" />
+            </el-checkbox-group>
+            <div class="text-sm text-gray-400">菜单内容最少选择2个</div>
+          </el-form-item>
+        </el-form>
       </div>
       </div>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="goodsStyleDialog = false">取消</el-button>
-          <el-button type="primary" @click="confirmGoodsStyle">确定</el-button>
-        </span>
-      </template>
-    </el-dialog>
-
-    <!-- 营销活动风格 -->
-    <el-dialog v-model="marketingStyleDialog" title="风格" width="460px">
-      <div class="flex flex-wrap">
-        <template v-for="(item, index) in Object.values(marketingGoodsStyleList)" :key="index">
-          <div
-            :class="{ 'border-primary': selectMarketingStyle.value == item.value }"
-            @click="changeMarketingStyle(item)"
-            class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]"
-          >
-            <img :src="img(item.url)" />
-          </div>
-        </template>
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">商品媒体</h3>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="商品主图">
+            <el-radio-group v-model="diyStore.editComponent.medium.type">
+              <el-radio value="square_img">固定方图</el-radio>
+              <el-radio value="height_adaptive">高度自适应</el-radio>
+              <div class="text-sm text-gray-400 leading-[1.6]">注意:高度自适应指商品主图的高度与第一张商品图的高度保持一致</div>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="轮播点">
+            <el-radio-group v-model="diyStore.editComponent.medium.indicator">
+              <el-radio :value="true">显示</el-radio>
+              <el-radio :value="false">隐藏</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
       </div>
       </div>
-      <template #footer>
-        <span class="dialog-footer">
-          <el-button @click="marketingStyleDialog = false">取消</el-button>
-          <el-button type="primary" @click="confirmMarketingStyle">确定</el-button>
-        </span>
-      </template>
-    </el-dialog>
-  </div>
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">价格展示</h3>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="展示方式">
+            <el-radio-group v-model="diyStore.editComponent.priceRegion.showWay">
+              <el-radio value="normal">常规</el-radio>
+              <el-radio value="fixed">置顶</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="edit-attr-item-wrap" v-if="diyStore.editComponent.priceRegion.showWay == 'fixed'">
+        <h3 class="mb-[10px]">普通价格背景图</h3>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="风格选择" class="flex">
+            <span class="text-primary flex-1 cursor-pointer" @click="showGoodsStyle">{{ diyStore.editComponent.priceRegion.goodsStyle.title }}</span>
+            <el-icon>
+              <ArrowRight />
+            </el-icon>
+          </el-form-item>
+          <el-form-item label="背景图片">
+            <upload-image v-model="diyStore.editComponent.priceRegion.bgImg" :limit="1" />
+            <div class="text-sm text-gray-400">背景图片推荐尺寸:750*148</div>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">销售信息</h3>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="是否展示">
+            <el-checkbox-group v-model="saleInfo" @change="saleInfoChange">
+              <el-checkbox label="划线价" value="underlined_price" />
+              <el-checkbox label="累计销量" value="sales" />
+              <el-checkbox label="库存" value="stock" />
+            </el-checkbox-group>
+          </el-form-item>
+        </el-form>
+      </div>
+      <!-- 普通商品风格 -->
+      <el-dialog v-model="goodsStyleDialog" title="selectStyle" width="460px">
+        <div class="flex flex-wrap">
+          <template v-for="(item, index) in Object.values(goodsStyleList)" :key="index">
+            <div
+              :class="{ 'border-primary': selectGoodsStyle.value == item.value }"
+              @click="changeGoodsStyle(item)"
+              class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]"
+            >
+              <img :src="img(item.url)" />
+            </div>
+          </template>
+        </div>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="goodsStyleDialog = false">取消</el-button>
+            <el-button type="primary" @click="confirmGoodsStyle">确定</el-button>
+          </span>
+        </template>
+      </el-dialog>
 
 
-  <!-- 样式 -->
-  <div class="style-wrap" v-show="diyStore.editTab == 'style'">
-    <!-- 价格模块样式 -->
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">价格样式</h3>
-      <div class="text-sm text-gray-400 mb-[10px] leading-[1.6]">仅在普通价格置顶时或营销活动开启的情况下生效</div>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="价格背景色">
-          <el-color-picker v-model="diyStore.editComponent.goodsInfo.priceBgColor" />
-        </el-form-item>
-        <el-form-item label="价格上圆角">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.priceTopRounded"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="0"
-            :max="100"
-          />
-        </el-form-item>
-        <el-form-item label="价格下圆角">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.priceBottomRounded"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="0"
-            :max="100"
-          />
-        </el-form-item>
-        <el-form-item label="上边距">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.priceTopMargin"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="-50"
-            :max="50"
-          />
-        </el-form-item>
-        <el-form-item label="左右边距">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.priceAboutMargin"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="0"
-            :max="20"
-          />
-        </el-form-item>
-      </el-form>
+      <!-- 营销活动风格 -->
+      <el-dialog v-model="marketingStyleDialog" title="风格" width="460px">
+        <div class="flex flex-wrap">
+          <template v-for="(item, index) in Object.values(marketingGoodsStyleList)" :key="index">
+            <div
+              :class="{ 'border-primary': selectMarketingStyle.value == item.value }"
+              @click="changeMarketingStyle(item)"
+              class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]"
+            >
+              <img :src="img(item.url)" />
+            </div>
+          </template>
+        </div>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="marketingStyleDialog = false">取消</el-button>
+            <el-button type="primary" @click="confirmMarketingStyle">确定</el-button>
+          </span>
+        </template>
+      </el-dialog>
     </div>
     </div>
-    <!-- 商品信息样式 -->
-    <div class="edit-attr-item-wrap">
-      <h3 class="mb-[10px]">商品信息样式</h3>
-      <el-form label-width="100px" class="px-[10px]">
-        <el-form-item label="标题颜色">
-          <el-color-picker v-model="diyStore.editComponent.goodsInfo.titleColor" />
-        </el-form-item>
-        <el-form-item label="副标题颜色">
-          <el-color-picker v-model="diyStore.editComponent.goodsInfo.subTitleColor" />
-        </el-form-item>
-        <el-form-item label="销售信息色">
-          <el-color-picker v-model="diyStore.editComponent.goodsInfo.saleInfoColor" />
-        </el-form-item>
-        <el-form-item label="商品背景色">
-          <el-color-picker v-model="diyStore.editComponent.goodsInfo.startBgColor" show-alpha :predefine="diyStore.predefineColors" />
-          <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
-          <el-color-picker v-model="diyStore.editComponent.goodsInfo.endBgColor" show-alpha :predefine="diyStore.predefineColors" />
-        </el-form-item>
-        <el-form-item label="商品上圆角">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.topRounded"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="0"
-            :max="100"
-          />
-        </el-form-item>
-        <el-form-item label="商品下圆角">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.bottomRounded"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="0"
-            :max="100"
-          />
-        </el-form-item>
-        <el-form-item label="上边距">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.topMargin"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="-50"
-            :max="50"
-          />
-        </el-form-item>
-        <el-form-item label="左右边距">
-          <el-slider
-            v-model="diyStore.editComponent.goodsInfo.aboutMargin"
-            show-input
-            size="small"
-            class="ml-[10px] diy-nav-slider"
-            :min="0"
-            :max="20"
-          />
-        </el-form-item>
-      </el-form>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <!-- 价格模块样式 -->
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">价格样式</h3>
+        <div class="text-sm text-gray-400 mb-[10px] leading-[1.6]">仅在普通价格置顶时或营销活动开启的情况下生效</div>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="价格背景色">
+            <el-color-picker v-model="diyStore.editComponent.goodsInfo.priceBgColor" />
+          </el-form-item>
+          <el-form-item label="价格上圆角">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.priceTopRounded"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="0"
+              :max="100"
+            />
+          </el-form-item>
+          <el-form-item label="价格下圆角">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.priceBottomRounded"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="0"
+              :max="100"
+            />
+          </el-form-item>
+          <el-form-item label="上边距">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.priceTopMargin"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="-50"
+              :max="50"
+            />
+          </el-form-item>
+          <el-form-item label="左右边距">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.priceAboutMargin"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="0"
+              :max="20"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <!-- 商品信息样式 -->
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">商品信息样式</h3>
+        <el-form label-width="100px" class="px-[10px]">
+          <el-form-item label="标题颜色">
+            <el-color-picker v-model="diyStore.editComponent.goodsInfo.titleColor" />
+          </el-form-item>
+          <el-form-item label="副标题颜色">
+            <el-color-picker v-model="diyStore.editComponent.goodsInfo.subTitleColor" />
+          </el-form-item>
+          <el-form-item label="销售信息色">
+            <el-color-picker v-model="diyStore.editComponent.goodsInfo.saleInfoColor" />
+          </el-form-item>
+          <el-form-item label="商品背景色">
+            <el-color-picker v-model="diyStore.editComponent.goodsInfo.startBgColor" show-alpha :predefine="diyStore.predefineColors" />
+            <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
+            <el-color-picker v-model="diyStore.editComponent.goodsInfo.endBgColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="商品上圆角">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.topRounded"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="0"
+              :max="100"
+            />
+          </el-form-item>
+          <el-form-item label="商品下圆角">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.bottomRounded"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="0"
+              :max="100"
+            />
+          </el-form-item>
+          <el-form-item label="上边距">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.topMargin"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="-50"
+              :max="50"
+            />
+          </el-form-item>
+          <el-form-item label="左右边距">
+            <el-slider
+              v-model="diyStore.editComponent.goodsInfo.aboutMargin"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="0"
+              :max="20"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
     </div>
     </div>
-    <!-- 组件样式 -->
-    <slot name="style"></slot>
   </div>
   </div>
 </template>
 </template>
 
 

+ 140 - 0
src/views/diy/components/edit-shop-goods-detail-bottom.vue

@@ -0,0 +1,140 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap goods-detail-bottom" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="是否显示">
+            <el-checkbox-group v-model="menuContent" @change="menuContentChange" :min="1" :max="3">
+              <el-checkbox label="首页" value="index" />
+              <el-checkbox label="客服" value="service" />
+              <el-checkbox label="购物车" value="cart" />
+              <el-checkbox label="收藏" value="collect" />
+              <el-checkbox label="分享" value="share" />
+            </el-checkbox-group>
+            <div class="text-sm text-gray-400">菜单内容最多选择3个,最少选择1个</div>
+          </el-form-item>
+          <el-form-item label="购物车按钮">
+            <el-radio-group v-model="diyStore.editComponent.cartIsShow">
+              <el-radio :value="true">显示</el-radio>
+              <el-radio :value="false">隐藏</el-radio>
+            </el-radio-group>
+            <div class="text-sm text-gray-400">注意:该设置在实物商品或虚拟商品且不核销的情况下生效</div>
+          </el-form-item>
+          <el-form-item label="购物车名称" v-show="diyStore.editComponent.cartIsShow">
+            <el-input v-model.trim="diyStore.editComponent.cartName" placeholder="请输入按钮文字" clearable maxlength="5" show-word-limit />
+          </el-form-item>
+          <el-form-item label="购买名称">
+            <el-input v-model.trim="diyStore.editComponent.buyName" placeholder="请输入按钮文字" clearable maxlength="5" show-word-limit />
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <div class="edit-attr-item-wrap" v-if="diyStore.editComponent.cartIsShow">
+        <h3 class="mb-[10px]">加入购物车</h3>
+        <el-form label-width="90px" class="px-[10px]">
+          <el-form-item label="文字大小">
+            <el-slider
+              v-model="diyStore.editComponent.cartStyle.fontSize"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="12"
+              :max="15"
+            />
+          </el-form-item>
+          <el-form-item label="标题颜色">
+            <el-color-picker v-model="diyStore.editComponent.cartStyle.textColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="渐变角度">
+            <el-radio-group v-model="diyStore.editComponent.cartStyle.gradientAngle">
+              <el-radio value="to bottom">从上到下</el-radio>
+              <el-radio value="to right">从左到右</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="背景颜色">
+            <el-color-picker v-model="diyStore.editComponent.cartStyle.startColor" show-alpha :predefine="diyStore.predefineColors" />
+            <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
+            <el-color-picker v-model="diyStore.editComponent.cartStyle.endColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">立即购买</h3>
+        <el-form label-width="90px" class="px-[10px]">
+          <el-form-item label="文字大小">
+            <el-slider
+              v-model="diyStore.editComponent.buyStyle.fontSize"
+              show-input
+              size="small"
+              class="ml-[10px] diy-nav-slider"
+              :min="12"
+              :max="15"
+            />
+          </el-form-item>
+          <el-form-item label="文字颜色">
+            <el-color-picker v-model="diyStore.editComponent.buyStyle.textColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+          <el-form-item label="渐变角度">
+            <el-radio-group v-model="diyStore.editComponent.buyStyle.gradientAngle">
+              <el-radio value="to bottom">从上到下</el-radio>
+              <el-radio value="to right">从左到右</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="背景颜色">
+            <el-color-picker v-model="diyStore.editComponent.buyStyle.startColor" show-alpha :predefine="diyStore.predefineColors" />
+            <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
+            <el-color-picker v-model="diyStore.editComponent.buyStyle.endColor" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+        </el-form>
+      </div>
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import useDiyStore from '@/store/modules/diy';
+import { ref, onMounted } from 'vue';
+
+const diyStore: any = useDiyStore();
+diyStore.editComponent.ignore = ['pageBgColor', 'componentBgUrl', 'marginTop', 'marginBottom', 'marginBoth', 'topRounded', 'bottomRounded']; // 忽略公共属性
+
+// 组件验证
+diyStore.editComponent.verify = (index: number) => {
+  const res = { code: true, message: '' };
+  return res;
+};
+
+const initFn = () => {
+  if (diyStore.editComponent.menuContent) {
+    menuContent.value =
+      typeof diyStore.editComponent.menuContent == 'object' ? diyStore.editComponent.menuContent : diyStore.editComponent.menuContent.split(',');
+  }
+};
+
+// 菜单内容
+const menuContent = ref([]);
+const menuContentChange = (val: any) => {
+  diyStore.editComponent.menuContent = val;
+};
+
+onMounted(() => {
+  initFn();
+});
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>
+<style lang="scss">
+.goods-detail-bottom {
+  .el-form-item__label {
+    width: 100px !important;
+  }
+}
+</style>

+ 40 - 0
src/views/diy/components/edit-shop-goods-detail-desc.vue

@@ -0,0 +1,40 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="是否显示">
+            <el-radio-group v-model="diyStore.editComponent.isShow">
+              <el-radio :value="true">显示</el-radio>
+              <el-radio :value="false">隐藏</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import useDiyStore from '@/store/modules/diy';
+
+const diyStore: any = useDiyStore();
+diyStore.editComponent.ignore = []; // 忽略公共属性
+
+// 组件验证
+diyStore.editComponent.verify = (index: number) => {
+  const res = { code: true, message: '' };
+  return res;
+};
+
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>

+ 40 - 0
src/views/diy/components/edit-shop-goods-detail-evaluate.vue

@@ -0,0 +1,40 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="是否显示">
+            <el-radio-group v-model="diyStore.editComponent.isShow">
+              <el-radio :value="true">显示</el-radio>
+              <el-radio :value="false">隐藏</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import useDiyStore from '@/store/modules/diy';
+
+const diyStore: any = useDiyStore();
+diyStore.editComponent.ignore = []; // 忽略公共属性
+
+// 组件验证
+diyStore.editComponent.verify = (index: number) => {
+  const res = { code: true, message: '' };
+  return res;
+};
+
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>

+ 54 - 0
src/views/diy/components/edit-shop-goods-detail-purchase-service.vue

@@ -0,0 +1,54 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="是否显示">
+            <el-checkbox-group v-model="serviceConfig" @change="serviceConfigChange" :min="2">
+              <el-checkbox label="商品服务" value="goods_service" />
+              <el-checkbox label="规格选择" value="spec_select" />
+              <el-checkbox label="配送信息" value="delivery_info" />
+              <el-checkbox label="领券(领取优惠券)" value="coupons" />
+              <el-checkbox label="优惠活动展示" value="activity" />
+            </el-checkbox-group>
+            <div class="text-sm text-gray-400">商品服务最少选择2个</div>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import useDiyStore from '@/store/modules/diy';
+import { ref, reactive } from 'vue';
+
+const diyStore: any = useDiyStore();
+diyStore.editComponent.ignore = []; // 忽略公共属性
+
+const serviceConfig = ref([]);
+if (diyStore.editComponent.serviceConfig) {
+  serviceConfig.value =
+    typeof diyStore.editComponent.serviceConfig == 'object' ? diyStore.editComponent.serviceConfig : diyStore.editComponent.serviceConfig.split(',');
+}
+const serviceConfigChange = (val: any) => {
+  diyStore.editComponent.serviceConfig = val;
+};
+
+// 组件验证
+diyStore.editComponent.verify = (index: number) => {
+  const res = { code: true, message: '' };
+  return res;
+};
+
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>

+ 56 - 0
src/views/diy/components/edit-shop-member-info.vue

@@ -0,0 +1,56 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">会员样式</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="背景图片">
+            <upload-image v-model="diyStore.editComponent.bgUrl" :limit="1" />
+          </el-form-item>
+        </el-form>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="账号信息">
+            <el-switch v-model="diyStore.editComponent.isShowAccount" />
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">会员样式</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="文字颜色">
+            <el-color-picker v-model="diyStore.editComponent.textColor" />
+          </el-form-item>
+        </el-form>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="编号颜色">
+            <el-color-picker v-model="diyStore.editComponent.uidTextColor" />
+          </el-form-item>
+        </el-form>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="账户颜色">
+            <el-color-picker v-model="diyStore.editComponent.accountTextColor" />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import useDiyStore from '@/store/modules/diy';
+
+const diyStore = useDiyStore();
+diyStore.editComponent.ignore = ['componentBgUrl']; // 忽略公共属性
+
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>

+ 86 - 0
src/views/diy/components/edit-shop-order-info.vue

@@ -0,0 +1,86 @@
+<template>
+  <div>
+    <!-- 内容 -->
+    <div class="content-wrap" v-show="diyStore.editTab == 'content'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">标题内容</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="标题名称">
+            <el-input v-model.trim="diyStore.editComponent.text" placeholder="请输入标题" clearable maxlength="6" show-word-limit />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">副标题</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="文字">
+            <el-input v-model.trim="diyStore.editComponent.more.text" placeholder="请输入文字" clearable maxlength="8" show-word-limit />
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+    <!-- 样式 -->
+    <div class="style-wrap" v-show="diyStore.editTab == 'style'">
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">标题样式</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="文字大小">
+            <el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="30" />
+          </el-form-item>
+          <el-form-item label="文字粗细">
+            <el-radio-group v-model="diyStore.editComponent.fontWeight">
+              <el-radio :value="'normal'">常规</el-radio>
+              <el-radio :value="'bold'">加粗</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="文字颜色">
+            <el-color-picker v-model="diyStore.editComponent.textColor" />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">副标题样式</h3>
+        <el-form label-width="80px" class="px-[10px]">
+          <el-form-item label="文字颜色">
+            <el-color-picker v-model="diyStore.editComponent.more.color" />
+          </el-form-item>
+        </el-form>
+      </div>
+
+      <div class="edit-attr-item-wrap">
+        <h3 class="mb-[10px]">文字设置</h3>
+        <el-form label-width="90px" class="px-[10px]">
+          <el-form-item label="文字大小">
+            <el-slider v-model="diyStore.editComponent.item.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16" />
+          </el-form-item>
+          <el-form-item label="文字粗细">
+            <el-radio-group v-model="diyStore.editComponent.item.fontWeight">
+              <el-radio :value="'normal'">常规</el-radio>
+              <el-radio :value="'bold'">加粗</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="文字颜色">
+            <el-color-picker v-model="diyStore.editComponent.item.color" show-alpha :predefine="diyStore.predefineColors" />
+          </el-form-item>
+        </el-form>
+      </div>
+      <!-- 组件样式 -->
+      <slot name="style"></slot>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { ref } from 'vue';
+import useDiyStore from '@/store/modules/diy';
+
+const diyStore = useDiyStore();
+diyStore.editComponent.ignore = ['componentBgUrl']; // 忽略公共属性
+
+defineExpose({});
+</script>
+
+<style lang="scss" scoped></style>

+ 1829 - 1
src/views/diy/edit.ts

@@ -653,10 +653,11 @@ export const data1 = {
           'uses': 0,
           'uses': 0,
           'value': {
           'value': {
             'style': 'style-1',
             'style': 'style-1',
-            'source': 'all',
+            'source': 1,
             'num': 10,
             'num': 10,
             'goods_category': '',
             'goods_category': '',
             'goods_category_name': '请选择',
             'goods_category_name': '请选择',
+            'goodsIds': [],
             'goods_ids': [],
             'goods_ids': [],
             'sortWay': 'default',
             'sortWay': 'default',
             'goodsNameStyle': {
             'goodsNameStyle': {
@@ -1598,3 +1599,1830 @@ export const data2 = {
     }
     }
   }
   }
 };
 };
+
+export const data3 = {
+  'global': {
+    'title': '首页',
+    'pageStartBgColor': 'rgba(246, 246, 246, 1)',
+    'pageEndBgColor': '',
+    'pageGradientAngle': 'to bottom',
+    'bgUrl': '',
+    'bgHeightScale': 100,
+    'imgWidth': '',
+    'imgHeight': '',
+    'topStatusBar': {
+      'control': true,
+      'isShow': false,
+      'bgColor': '#ffffff',
+      'rollBgColor': '#ffffff',
+      'style': 'style-1',
+      'styleName': '风格1',
+      'textColor': '#333333',
+      'rollTextColor': '#333333',
+      'textAlign': 'center',
+      'inputPlaceholder': '请输入搜索关键词',
+      'imgUrl': '',
+      'link': {
+        'name': ''
+      }
+    },
+    'bottomTabBar': {
+      'control': true,
+      'isShow': true,
+      'designNav': {
+        'title': '',
+        'key': ''
+      }
+    },
+    'copyright': {
+      'control': true,
+      'isShow': false,
+      'textColor': '#ccc'
+    },
+    'popWindow': {
+      'imgUrl': '',
+      'imgWidth': '',
+      'imgHeight': '',
+      'count': 'once',
+      'show': 0,
+      'link': {
+        'name': ''
+      }
+    },
+    'template': {
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 0
+      }
+    }
+  },
+  'value': [
+    {
+      'path': 'edit-carousel-search',
+      'uses': 1,
+      'position': 'top_fixed',
+      'id': '6r6qw5679oo0',
+      'componentName': 'CarouselSearch',
+      'componentTitle': '轮播搜索',
+      'ignore': ['componentBgColor', 'componentBgUrl', 'marginTop', 'marginBottom', 'topRounded', 'bottomRounded', 'pageBgColor', 'marginBoth'],
+      'positionWay': 'fixed',
+      'fixedBgColor': '',
+      'bgGradient': false,
+      'search': {
+        'logo': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/logo.png',
+        'text': '请输入搜索关键词',
+        'link': '',
+        'style': 'style-2',
+        'styleName': '风格2',
+        'subTitle': {
+          'text': '本地好价·优选生活',
+          'textColor': '#000000',
+          'startColor': 'rgba(255,255,255,0.7)',
+          'endColor': ''
+        },
+        'positionColor': '#ffffff',
+        'hotWord': {
+          'interval': 3,
+          'list': [
+            {
+              'text': '新品推荐',
+              'id': '1l3juvqvimw0'
+            },
+            {
+              'text': '爆款',
+              'id': '2vejp61n1xk0'
+            }
+          ]
+        },
+        'color': '#999999',
+        'btnColor': '#ffffff',
+        'bgColor': '#ffffff',
+        'btnBgColor': '#ff3434'
+      },
+      'tab': {
+        'control': false,
+        'noColor': 'rgba(255, 255, 255, 0.7)',
+        'selectColor': 'rgba(255, 255, 255, 1)',
+        'fixedNoColor': 'rgba(255, 255, 255, 0.7)',
+        'fixedSelectColor': 'rgba(255, 255, 255, 1)',
+        'list': [
+          {
+            'text': '精选',
+            'source': 'diy_page',
+            'diy_id': '',
+            'diy_title': '',
+            'id': '1wx7m1wykqbk'
+          },
+          {
+            'text': '猜你喜欢',
+            'source': 'diy_page',
+            'diy_id': '',
+            'diy_title': '',
+            'id': '1gfh1oc6fsjk'
+          },
+          {
+            'text': '蔬菜',
+            'source': 'diy_page',
+            'diy_id': '',
+            'diy_title': '',
+            'id': '25v390lfsd34'
+          },
+          {
+            'text': '水果',
+            'source': 'diy_page',
+            'diy_id': '',
+            'diy_title': '',
+            'id': '2zb1znvn5jc0'
+          },
+          {
+            'id': '5acf7ab4f040',
+            'text': '海鲜',
+            'source': 'diy_page',
+            'diy_id': 0,
+            'diy_title': ''
+          },
+          {
+            'id': '37a9vwqt1r20',
+            'text': '熟食',
+            'source': 'diy_page',
+            'diy_id': 0,
+            'diy_title': ''
+          },
+          {
+            'id': '1en9w5jstvs0',
+            'text': '米面',
+            'source': 'diy_page',
+            'diy_id': 0,
+            'diy_title': ''
+          },
+          {
+            'id': '3ae14irgqoa0',
+            'text': '粮油',
+            'source': 'diy_page',
+            'diy_id': 0,
+            'diy_title': ' '
+          }
+        ]
+      },
+      'swiper': {
+        'control': true,
+        'interval': 5,
+        'indicatorColor': 'rgba(255, 255, 255, 1)',
+        'indicatorActiveColor': '#FF0E0E',
+        'indicatorStyle': 'style-3',
+        'indicatorAlign': 'center',
+        'swiperStyle': 'style-3',
+        'imageHeight': 274,
+        'topRounded': 0,
+        'bottomRounded': 0,
+        'list': [
+          {
+            'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/banner1.jpg',
+            'imgWidth': 750,
+            'imgHeight': 580,
+            'link': '',
+            'id': '397htiaqung0',
+            'width': 355,
+            'height': 274.53
+          },
+          {
+            'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/banner2.jpg',
+            'imgWidth': 750,
+            'imgHeight': 580,
+            'link': '',
+            'id': '6mrj3vwiamw0',
+            'width': 355,
+            'height': 274.53
+          }
+        ]
+      },
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 0
+      },
+      'pageStyle': 'padding-top:2rpx;padding-bottom:0rpx;padding-right:0rpx;padding-left:0rpx;'
+    },
+    {
+      'path': 'edit-horz-blank',
+      'uses': 0,
+      'id': '4wk9nzocm3c',
+      'componentName': 'HorzBlank',
+      'componentTitle': '辅助空白',
+      'ignore': ['pageBgColor', 'componentBgUrl'],
+      'height': 22,
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': 'rgba(246, 246, 246, 1)',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 17,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': -21,
+        'bottom': 0,
+        'both': 0
+      },
+      'pageStyle': 'padding-top:2rpx;padding-bottom:0rpx;padding-right:0rpx;padding-left:0rpx;'
+    },
+    {
+      'path': 'edit-graphic-nav',
+      'uses': 0,
+      'id': '6h28ebyqqnk0',
+      'componentName': 'GraphicNav',
+      'componentTitle': '图文导航',
+      'ignore': [],
+      'layout': 'horizontal',
+      'mode': 'graphic',
+      'showStyle': 'fixed',
+      'rowCount': 5,
+      'pageCount': 2,
+      'carousel': {
+        'type': 'circle',
+        'color': '#FFFFFF'
+      },
+      'imageSize': 40,
+      'aroundRadius': 25,
+      'font': {
+        'size': 12,
+        'weight': 'normal',
+        'color': '#303133'
+      },
+      'list': [
+        {
+          'title': '签到',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_sign_in.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '1evjnc3zeb5s',
+          'imgWidth': 180,
+          'imgHeight': 180
+        },
+        {
+          'title': '分销管理',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_fenxiao.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '2ktzer8wrnc0',
+          'imgWidth': 180,
+          'imgHeight': 180
+        },
+        {
+          'title': '分销专区',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_fenxiao_zone.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '4aixr8qu5ek0',
+          'imgWidth': 180,
+          'imgHeight': 180
+        },
+        {
+          'title': '领券中心',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_coupon.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '3bmtyrslxxy0',
+          'imgWidth': 180,
+          'imgHeight': 180
+        },
+        {
+          'id': '6iux9g1aojo0',
+          'title': '新闻资讯',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_news_info.png',
+          'imgWidth': 180,
+          'imgHeight': 180,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '7jggy5euv3w0',
+          'title': '限时折扣',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_discount.png',
+          'imgWidth': 180,
+          'imgHeight': 180,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '7bqpc6bjha80',
+          'title': '积分商城',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_point_index.png',
+          'imgWidth': 180,
+          'imgHeight': 180,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': 'tgo5qmjawnk',
+          'title': '礼品卡',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_giftcard.png',
+          'imgWidth': 180,
+          'imgHeight': 180,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '1fprven2cqrk',
+          'title': '新人专享',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_my_newcomer.png',
+          'imgWidth': 180,
+          'imgHeight': 180,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '2wggehpnako0',
+          'title': '限时秒杀',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/nav_seckill.png',
+          'imgWidth': 180,
+          'imgHeight': 180,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        }
+      ],
+      'swiper': {
+        'indicatorColor': 'rgba(0, 0, 0, 0.3)',
+        'indicatorActiveColor': '#FF0E0E',
+        'indicatorStyle': 'style-1',
+        'indicatorAlign': 'center'
+      },
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 12,
+      'bottomRounded': 12,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': -10,
+        'bottom': 10,
+        'both': 10
+      },
+      'pageStyle': 'padding-top:2rpx;padding-bottom:0rpx;padding-right:0rpx;padding-left:0rpx;'
+    },
+    {
+      'path': 'edit-notice',
+      'uses': 0,
+      'id': '5ux60nfdm680',
+      'componentName': 'Notice',
+      'componentTitle': '公告',
+      'ignore': [],
+      'noticeType': 'img',
+      'imgType': 'diy',
+      'systemUrl': 'style_1',
+      'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/notice.png',
+      'showType': 'popup',
+      'scrollWay': 'upDown',
+      'fontSize': 12,
+      'fontWeight': 'normal',
+      'noticeTitle': '公告',
+      'list': [
+        {
+          'text': '最新公告:欢迎来到小店参观!',
+          'link': {
+            'name': ''
+          },
+          'id': '1rz6s4buaxc0'
+        },
+        {
+          'id': '2wksdax75fc0',
+          'text': '最新公告:欢迎来到小店参观!',
+          'link': {
+            'name': ''
+          }
+        }
+      ],
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 12,
+      'bottomRounded': 12,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStyle': 'padding-top:2rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    },
+    {
+      'path': 'edit-goods-coupon',
+      'uses': 0,
+      'id': '5zq2inzbmu00',
+      'componentName': 'GoodsCoupon',
+      'componentTitle': '优惠券',
+      'ignore': ['componentBgColor', 'componentBgUrl'],
+      'style': 'style-3',
+      'styleName': '风格3',
+      'source': 'all',
+      'num': 6,
+      'couponIds': [],
+      'btnText': '立即领取',
+      'couponTitle': '每日省钱',
+      'couponSubTitle': '先领券 再购物',
+      'titleColor': '#ffffff',
+      'subTitleColor': '#ffffff',
+      'couponItem': {
+        'bgColor': '#ffffff',
+        'textColor': '#333333',
+        'subTextColor': '#666666',
+        'moneyColor': '#333333',
+        'aroundRadius': 12
+      },
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 12,
+      'bottomRounded': 12,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 10,
+        'bottom': null,
+        'both': 10
+      },
+      'pageStyle': 'padding-top:20rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    },
+    {
+      'path': 'edit-shop-goods-recommend',
+      'uses': 0,
+      'id': '2ezdal8ps1og',
+      'componentName': 'ShopGoodsRecommend',
+      'componentTitle': '商品推荐',
+      'mode': 'aspectFill',
+      'ignore': [],
+      'priceStyle': {
+        'mainColor': '#333333'
+      },
+      'source': 'all',
+      'goods_ids': [],
+      'list': [
+        {
+          'title': {
+            'text': '今日推荐',
+            'textColor': '#303133'
+          },
+          'moreTitle': {
+            'text': '精选',
+            'textColor': '#FFFFFF',
+            'startColor': '#FF7234',
+            'endColor': '#FF213F'
+          },
+          'listFrame': {
+            'startColor': '#FFE5E5',
+            'endColor': '#FFF5F0'
+          },
+          'button': {
+            'text': '首单',
+            'textColor': '#FFFFFF',
+            'color': '#FF1128'
+          },
+          'id': '6t9kv928d680'
+        },
+        {
+          'title': {
+            'text': '品质好物',
+            'textColor': '#303133'
+          },
+          'moreTitle': {
+            'text': '精选',
+            'textColor': '#FFFFFF',
+            'startColor': '#F2C719',
+            'endColor': '#FBBA08'
+          },
+          'listFrame': {
+            'startColor': '#FFEFBA',
+            'endColor': '#FFF5D7'
+          },
+          'button': {
+            'text': '首单',
+            'textColor': '#FFFFFF',
+            'color': '#FF1128'
+          },
+          'id': '4u1rv0e4qpo0'
+        },
+        {
+          'title': {
+            'text': '热销爆款',
+            'textColor': '#303133'
+          },
+          'moreTitle': {
+            'text': '精选',
+            'textColor': '#FFFFFF',
+            'startColor': '#FFA629',
+            'endColor': '#FF8E1E'
+          },
+          'listFrame': {
+            'startColor': '#FFE4D9',
+            'endColor': '#FFFBF9'
+          },
+          'button': {
+            'text': '首单',
+            'textColor': '#FFFFFF',
+            'color': '#FF1128'
+          },
+          'id': '4v1bhzhxay60'
+        }
+      ],
+      'imgElementRounded': 10,
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 10,
+      'bottomElementRounded': 10,
+      'margin': {
+        'top': 10,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStyle': 'padding-top:20rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    },
+    {
+      'path': 'edit-active-cube',
+      'uses': 0,
+      'id': '3vmpaydr2a60',
+      'componentName': 'ActiveCube',
+      'componentTitle': '活动魔方',
+      'ignore': [],
+      'titleStyle': {
+        'title': '风格5',
+        'value': 'style-5'
+      },
+      'text': '超值爆款',
+      'textLink': {
+        'name': ''
+      },
+      'titleColor': '#F91700',
+      'subTitle': {
+        'text': '为您精选爆款',
+        'textColor': 'rgba(153, 153, 153, 1)',
+        'startColor': 'rgba(255, 255, 255, 1)',
+        'endColor': 'rgba(255, 255, 255, 1)',
+        'link': {
+          'name': ''
+        }
+      },
+      'blockStyle': {
+        'title': '风格2',
+        'value': 'style-2',
+        'fontWeight': 'bold',
+        'btnText': 'italics'
+      },
+      'list': [
+        {
+          'title': {
+            'text': '品质好物',
+            'textColor': '#303133'
+          },
+          'subTitle': {
+            'text': '品质好物推荐',
+            'textColor': '#999999',
+            'startColor': '',
+            'endColor': ''
+          },
+          'moreTitle': {
+            'text': 'GO!',
+            'startColor': '#FFC051',
+            'endColor': '#FF9C00'
+          },
+          'listFrame': {
+            'startColor': '#FFF1DB',
+            'endColor': '#FFFBF4'
+          },
+          'link': {
+            'name': ''
+          },
+          'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/active_cube/active_cube_goods1.png',
+          'id': '77tls7gaho80'
+        },
+        {
+          'title': {
+            'text': '热销推荐',
+            'textColor': '#303133'
+          },
+          'subTitle': {
+            'text': '本周热销商品',
+            'textColor': '#999999',
+            'startColor': '',
+            'endColor': ''
+          },
+          'moreTitle': {
+            'text': 'GO!',
+            'startColor': '#A4E894',
+            'endColor': '#45CC2A'
+          },
+          'listFrame': {
+            'startColor': '#E6F6E2',
+            'endColor': '#F5FDF3'
+          },
+          'link': {
+            'name': ''
+          },
+          'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/active_cube/active_cube_goods2.png',
+          'id': 'm4scwuc67do'
+        },
+        {
+          'title': {
+            'text': '优惠好物',
+            'textColor': '#303133'
+          },
+          'subTitle': {
+            'text': '领券后更优惠',
+            'textColor': '#999999',
+            'startColor': '',
+            'endColor': ''
+          },
+          'moreTitle': {
+            'text': 'GO!',
+            'startColor': '#4BC2FF',
+            'endColor': '#1F7DFF'
+          },
+          'listFrame': {
+            'startColor': '#E2F6FF',
+            'endColor': '#F2FAFF'
+          },
+          'link': {
+            'name': ''
+          },
+          'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/active_cube/active_cube_goods3.png',
+          'id': '33nbfp8czea0'
+        },
+        {
+          'title': {
+            'text': '今日推荐',
+            'textColor': '#303133'
+          },
+          'subTitle': {
+            'text': '诚意推荐',
+            'textColor': '#999999',
+            'startColor': '',
+            'endColor': ''
+          },
+          'moreTitle': {
+            'text': 'GO!',
+            'startColor': '#FB792F',
+            'endColor': '#F91700'
+          },
+          'listFrame': {
+            'startColor': '#FFEAEA',
+            'endColor': '#FFFCFB'
+          },
+          'link': {
+            'name': ''
+          },
+          'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/active_cube/active_cube_goods4.png',
+          'id': '49scoy4bgsg0'
+        }
+      ],
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 12,
+      'bottomRounded': 12,
+      'elementBgColor': '#FFFAF5',
+      'topElementRounded': 10,
+      'bottomElementRounded': 10,
+      'margin': {
+        'top': 10,
+        'bottom': 0,
+        'both': 10
+      },
+      'textImg': 'https://v6.site.niucloud.com/static/resource/images/diy/active_cube/active_cube_text1.png',
+      'contentBtnTextStyle': 'italics',
+      'pageStyle': 'padding-top:20rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    },
+    {
+      'path': 'edit-picture-show',
+      'uses': 0,
+      'id': '2o99dw6mytk0',
+      'componentName': 'PictureShow',
+      'componentTitle': '图片展播',
+      'ignore': [],
+      'moduleOne': {
+        'head': {
+          'textImg': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_show_head_text1.png',
+          'subText': '每日上新',
+          'subTextColor': '#666666'
+        },
+        'list': [
+          {
+            'btnTitle': {
+              'text': '仅限今日',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_01.png'
+          },
+          {
+            'btnTitle': {
+              'text': '超值上新',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_02.png'
+          }
+        ],
+        'listFrame': {
+          'startColor': '#FFDDDD',
+          'endColor': '#FFEBED'
+        }
+      },
+      'moduleTwo': {
+        'head': {
+          'textImg': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_show_head_text2.png',
+          'subText': '好物低至1折1',
+          'subTextColor': '#666666'
+        },
+        'list': [
+          {
+            'btnTitle': {
+              'text': '大牌直降',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_03.png'
+          },
+          {
+            'btnTitle': {
+              'text': '天天底价',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_04.png'
+          }
+        ],
+        'listFrame': {
+          'startColor': '#E6E1FE',
+          'endColor': '#F0EEFC'
+        }
+      },
+      'moduleRounded': {
+        'topRounded': 10,
+        'bottomRounded': 10
+      },
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 10,
+        'bottom': null,
+        'both': 10
+      },
+      'pageStyle': 'padding-top:20rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    },
+    {
+      'path': 'edit-picture-show',
+      'uses': 0,
+      'id': '3wz1r5bww3q0',
+      'componentName': 'PictureShow',
+      'componentTitle': '图片展播',
+      'ignore': [],
+      'moduleOne': {
+        'head': {
+          'textImg': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_show_head_text3.png',
+          'subText': '最高补1200元',
+          'subTextColor': '#666666'
+        },
+        'list': [
+          {
+            'btnTitle': {
+              'text': '全网低价',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_05.png'
+          },
+          {
+            'btnTitle': {
+              'text': '大牌特惠',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_06.png'
+          }
+        ],
+        'listFrame': {
+          'startColor': 'rgba(212, 239, 255, 1)',
+          'endColor': 'rgba(235, 244, 250, 1)'
+        }
+      },
+      'moduleTwo': {
+        'head': {
+          'textImg': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_show_head_text4.png',
+          'subText': '每日上新',
+          'subTextColor': '#666666'
+        },
+        'list': [
+          {
+            'btnTitle': {
+              'text': '人气爆款',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_07.png'
+          },
+          {
+            'btnTitle': {
+              'text': '官方正品',
+              'color': '#ffffff',
+              'startColor': '#F5443E',
+              'endColor': '#F5443E'
+            },
+            'link': {
+              'name': ''
+            },
+            'imageUrl': 'https://v6.site.niucloud.com/static/resource/images/diy/picture_show/picture_08.png'
+          }
+        ],
+        'listFrame': {
+          'startColor': 'rgba(255, 241, 212, 1)',
+          'endColor': 'rgba(249, 242, 229, 1)'
+        }
+      },
+      'moduleRounded': {
+        'topRounded': 10,
+        'bottomRounded': 10
+      },
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 10,
+        'bottom': null,
+        'both': 10
+      },
+      'pageStyle': 'padding-top:20rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    },
+    // {
+    //   'path': 'edit-single-recommend',
+    //   'uses': 0,
+    //   'id': '2mxsu6pbqpu0',
+    //   'componentName': 'SingleRecommend',
+    //   'mode': 'aspectFill',
+    //   'componentTitle': '精选推荐',
+    //   'ignore': [],
+    //   'titleStyle': {
+    //     'title': '风格1',
+    //     'value': 'style-1'
+    //   },
+    //   'textImg': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/single_recommend_text1.png',
+    //   'textLink': {
+    //     'name': ''
+    //   },
+    //   'titleColor': 'rgba(153, 153, 153, 1)',
+    //   'subTitle': {
+    //     'text': '更多',
+    //     'textColor': 'rgba(153, 153, 153, 1)',
+    //     'link': {
+    //       'name': ''
+    //     }
+    //   },
+    //   'source': 'all',
+    //   'goods_ids': [],
+    //   'imageHeight': '250',
+    //   'list': [
+    //     {
+    //       'id': '18o4pyaufktc',
+    //       'imageUrl': 'addon/shop/diy/index/style3/single_recommend_banner1.jpg',
+    //       'imgWidth': 345,
+    //       'imgHeight': 495,
+    //       'link': {
+    //         'name': ''
+    //       },
+    //       'width': 355,
+    //       'height': 509.3478260869565
+    //     },
+    //     {
+    //       'id': '18o8pyaufktc',
+    //       'imageUrl': 'addon/shop/diy/index/style3/single_recommend_banner2.jpg',
+    //       'imgWidth': 345,
+    //       'imgHeight': 495,
+    //       'link': {
+    //         'name': ''
+    //       },
+    //       'width': 355,
+    //       'height': 509.3478260869565
+    //     }
+    //   ],
+    //   'goodsNameStyle': {
+    //     'color': '#303133',
+    //     'control': true,
+    //     'fontWeight': 'normal'
+    //   },
+    //   'priceStyle': {
+    //     'mainColor': '#FF4142',
+    //     'mainControl': true,
+    //     'lineColor': '#999CA7',
+    //     'lineControl': true
+    //   },
+    //   'saleStyle': {
+    //     'color': 'rgba(255, 0, 0, 1)',
+    //     'control': true
+    //   },
+    //   'textColor': '#303133',
+    //   'pageStartBgColor': '',
+    //   'pageEndBgColor': '',
+    //   'pageGradientAngle': 'to bottom',
+    //   'componentBgUrl': '',
+    //   'componentBgAlpha': 2,
+    //   'componentStartBgColor': null,
+    //   'componentEndBgColor': null,
+    //   'componentGradientAngle': 'to bottom',
+    //   'topRounded': 0,
+    //   'bottomRounded': 0,
+    //   'elementBgColor': 'rgba(255, 255, 255, 1)',
+    //   'topElementRounded': 12,
+    //   'bottomElementRounded': 12,
+    //   'margin': {
+    //     'top': 15,
+    //     'bottom': 0,
+    //     'both': 10
+    //   },
+    //   'pageStyle': 'padding-top:20rpx;padding-bottom:20rpx;padding-right:20rpx;padding-left:20rpx;',
+    //   'topCarouselRounded': 12,
+    //   'bottomCarouselRounded': 12,
+    //   'indicatorColor': 'rgba(255, 255, 255, 0.6)',
+    //   'indicatorActiveColor': 'rgba(255, 255, 255, 1)'
+    // },
+    {
+      'path': 'edit-image-ads',
+      'uses': 0,
+      'id': '1kfmhruhijgg',
+      'componentName': 'ImageAds',
+      'componentTitle': '图片广告',
+      'ignore': [],
+      'imageHeight': 89,
+      'isSameScreen': false,
+      'list': [
+        {
+          'link': {
+            'name': ''
+          },
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/index/style3/discount_img.png',
+          'imgWidth': 710,
+          'imgHeight': 170,
+          'id': '6eo9vdo9xtc0',
+          'width': 375,
+          'height': 89.78873239436619
+        }
+      ],
+      'textColor': '#303133',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 10,
+        'bottom': 10,
+        'both': 10
+      }
+    },
+    {
+      'path': 'edit-many-goods-list',
+      'uses': 0,
+      'id': '37adfqtqe080',
+      'componentName': 'ManyGoodsList',
+      'componentTitle': '多商品组',
+      'mode': 'aspectFill',
+      'ignore': ['componentBgUrl'],
+      'style': 'style-2',
+      'num': 6,
+      'sortWay': 'default',
+      'headStyle': 'style-4',
+      'aroundRadius': 25,
+      'source': 'custom',
+      'goods_category': '',
+      'goods_category_name': '请选择',
+      'goodsNameStyle': {
+        'color': '#303133',
+        'control': true,
+        'fontWeight': 'normal',
+        'isShow': true
+      },
+      'priceStyle': {
+        'color': '#FF4142',
+        'control': true,
+        'isShow': true
+      },
+      'saleStyle': {
+        'color': '#999999',
+        'control': true,
+        'isShow': true
+      },
+      'labelStyle': {
+        'control': true,
+        'isShow': true
+      },
+      'btnStyle': {
+        'fontWeight': false,
+        'padding': 0,
+        'aroundRadius': 25,
+        'cartEvent': 'detail',
+        'text': '购买',
+        'textColor': '#FFFFFF',
+        'startBgColor': '#FF4142',
+        'endBgColor': '#FF4142',
+        'style': 'nc-icon-gouwuche1',
+        'control': true
+      },
+      'imgElementRounded': 12,
+      'list': [
+        {
+          'title': '推荐',
+          'desc': '猜你喜欢',
+          'source': 'all',
+          'goods_category': '',
+          'goods_category_name': '请选择',
+          'goods_ids': [],
+          'imageUrl': '',
+          'id': '67pl1ysjhr40'
+        },
+        {
+          'id': '6z59zcmk4jk0',
+          'title': '衣鞋包饰',
+          'desc': '分类描述',
+          'source': 'all',
+          'goods_category': '',
+          'goods_category_name': '请选择',
+          'goods_ids': [],
+          'imageUrl': ''
+        },
+        {
+          'id': '1cfbll6wnmw0',
+          'title': '居家百货',
+          'desc': '分类描述',
+          'source': 'all',
+          'goods_category': '',
+          'goods_category_name': '请选择',
+          'goods_ids': [],
+          'imageUrl': ''
+        },
+        {
+          'id': '49p79g5l5qs0',
+          'title': '食品营养',
+          'desc': '分类描述',
+          'source': 'all',
+          'goods_category': '',
+          'goods_category_name': '请选择',
+          'goods_ids': [],
+          'imageUrl': ''
+        }
+      ],
+      'textColor': '#303133',
+      'pageStartBgColor': 'rgba(255, 255, 255, 1)',
+      'pageEndBgColor': 'rgba(255, 255, 255, 0.4)',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentStartBgColor': null,
+      'componentEndBgColor': null,
+      'componentGradientAngle': 'to bottom',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 12,
+      'bottomElementRounded': 12,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStyle':
+        'background:linear-gradient(to bottom,rgba(255, 255, 255, 1),rgba(255, 255, 255, 0.4));padding-top:2rpx;padding-bottom:0rpx;padding-right:20rpx;padding-left:20rpx;'
+    }
+  ]
+};
+
+export const data4 = {
+  'global': {
+    'title': '个人中心',
+    'bgUrl': '',
+    'imgWidth': '',
+    'imgHeight': '',
+    'bottomTabBar': {
+      'control': true,
+      'isShow': true,
+      'designNav': {
+        'title': '',
+        'key': ''
+      }
+    },
+    'copyright': {
+      'control': true,
+      'isShow': false,
+      'textColor': '#ccc'
+    },
+    'template': {
+      'textColor': '#303133',
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 0
+      },
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom'
+    },
+    'topStatusBar': {
+      'control': true,
+      'isShow': true,
+      'bgColor': '#ffffff',
+      'rollBgColor': '#ffffff',
+      'style': 'style-1',
+      'styleName': '风格1',
+      'textColor': '#333333',
+      'rollTextColor': '#333333',
+      'textAlign': 'center',
+      'inputPlaceholder': '请输入搜索关键词',
+      'imgUrl': '',
+      'link': {
+        'name': ''
+      }
+    },
+    'popWindow': {
+      'imgUrl': '',
+      'imgWidth': '',
+      'imgHeight': '',
+      'count': 'once',
+      'show': 0,
+      'link': {
+        'name': ''
+      }
+    },
+    'pageStartBgColor': 'rgba(246, 246, 246, 1)',
+    'pageEndBgColor': '',
+    'pageGradientAngle': 'to bottom',
+    'bgHeightScale': 0
+  },
+  'value': [
+    {
+      'path': 'edit-shop-member-info',
+      'id': '3pt9pn9bvn20',
+      'componentName': 'ShopMemberInfo',
+      'componentTitle': '会员信息',
+      'uses': 1,
+      'ignore': ['componentBgUrl'],
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': 'rgba(246, 246, 246, 0.1)',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 0
+      },
+      'textColor': '#333333',
+      'uidTextColor': '#666666',
+      'accountTextColor': '#666666',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom',
+      'style': 'style-1',
+      'styleName': '风格1',
+      'bgUrl': '',
+      'isShowAccount': true
+    },
+    {
+      'path': 'edit-member-level',
+      'uses': 1,
+      'id': '533e6ynytmo0',
+      'componentName': 'MemberLevel',
+      'componentTitle': '会员等级',
+      'ignore': ['componentBgColor', 'componentBgUrl'],
+      'style': 'style-5',
+      'styleName': '风格5',
+      'textColor': '#303133',
+      'componentStartBgColor': '',
+      'componentEndBgColor': '',
+      'topRounded': 12,
+      'bottomRounded': 12,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': -45,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom'
+    },
+    {
+      'path': 'edit-shop-order-info',
+      'uses': 1,
+      'id': '2jmnqqhc8ri0',
+      'componentName': 'ShopOrderInfo',
+      'componentTitle': '订单中心',
+      'ignore': [],
+      'textColor': '#303133',
+      'fontSize': 15,
+      'fontWeight': 'normal',
+      'text': '订单中心',
+      'more': {
+        'text': '全部订单',
+        'color': '#999999'
+      },
+      'item': {
+        'fontSize': 12,
+        'fontWeight': 'normal',
+        'color': '#303133'
+      },
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'topRounded': 12,
+      'bottomRounded': 12,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 10,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom'
+    },
+    {
+      'path': 'edit-horz-blank',
+      'uses': 0,
+      'id': '6cil3ipiis40',
+      'componentName': 'HorzBlank',
+      'componentTitle': '辅助空白',
+      'ignore': ['pageBgColor', 'componentBgUrl'],
+      'height': 10,
+      'textColor': '#303133',
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'topRounded': 12,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 10,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom'
+    },
+    {
+      'path': 'edit-text',
+      'uses': 0,
+      'id': '68gnubbygqg0',
+      'componentName': 'Text',
+      'componentTitle': '标题',
+      'ignore': [],
+      'textColor': '#303133',
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 10
+      },
+      'fontSize': 15,
+      'fontWeight': 'normal',
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom',
+      'position': '',
+      'style': 'style-1',
+      'styleName': '风格1',
+      'text': '其他功能',
+      'link': '',
+      'textAlign': 'left',
+      'subTitle': {
+        'text': '副标题',
+        'color': '#999999',
+        'fontSize': 14,
+        'control': false,
+        'fontWeight': 'normal'
+      },
+      'more': {
+        'text': '查看更多',
+        'control': false,
+        'isShow': true,
+        'link': '',
+        'color': '#999999'
+      }
+    },
+    {
+      'path': 'edit-horz-blank',
+      'uses': 0,
+      'id': '5jx57rrjl940',
+      'componentName': 'HorzBlank',
+      'componentTitle': '辅助空白',
+      'ignore': ['pageBgColor', 'componentBgUrl'],
+      'height': 8,
+      'textColor': '#303133',
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'topRounded': 0,
+      'bottomRounded': 0,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 0,
+        'both': 10
+      },
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom'
+    },
+    {
+      'path': 'edit-graphic-nav',
+      'uses': 0,
+      'id': '5myxk1opz0c0',
+      'componentName': 'GraphicNav',
+      'componentTitle': '图文导航',
+      'ignore': [],
+      'textColor': '#303133',
+      'componentStartBgColor': 'rgba(255, 255, 255, 1)',
+      'componentEndBgColor': '',
+      'topRounded': 0,
+      'bottomRounded': 12,
+      'elementBgColor': '',
+      'topElementRounded': 0,
+      'bottomElementRounded': 0,
+      'margin': {
+        'top': 0,
+        'bottom': 10,
+        'both': 10
+      },
+      'pageStartBgColor': '',
+      'pageEndBgColor': '',
+      'pageGradientAngle': 'to bottom',
+      'componentBgUrl': '',
+      'componentBgAlpha': 2,
+      'componentGradientAngle': 'to bottom',
+      'layout': 'horizontal',
+      'mode': 'graphic',
+      'showStyle': 'fixed',
+      'rowCount': 4,
+      'pageCount': 2,
+      'carousel': {
+        'type': 'circle',
+        'color': '#FFFFFF'
+      },
+      'imageSize': 20,
+      'aroundRadius': 0,
+      'font': {
+        'size': 12,
+        'weight': 'normal',
+        'color': '#303133'
+      },
+      'list': [
+        {
+          'id': '49kxbgr5lwue',
+          'title': '签到',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_sign_in.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'title': '我的余额',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_balance.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '2aqy33banse8',
+          'imgWidth': 92,
+          'imgHeight': 92
+        },
+        {
+          'title': '地址管理',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_address.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': 'hdk4145zk40',
+          'imgWidth': 92,
+          'imgHeight': 92
+        },
+        {
+          'title': '优惠券',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_coupon.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '34t5xg9ik0i0',
+          'imgWidth': 92,
+          'imgHeight': 92
+        },
+        {
+          'id': '7dpefp0s9ew0',
+          'title': '分销中心',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_promote.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'title': '积分兑换',
+          'link': '',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_point_change.png',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          },
+          'id': '692put4jerg0',
+          'imgWidth': 92,
+          'imgHeight': 92
+        },
+        {
+          'id': '78kxbgr4lipw',
+          'title': '核销台',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_verify_index.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '27kxbgr5lj3w',
+          'title': '礼品卡',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_giftcard.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '4o2q7yss59m0',
+          'title': '我的等级',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_my_level.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '78fnsh8cx5k0',
+          'title': '我的收藏',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_collect.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '38fqtyu8cx5k0',
+          'title': '我的足迹',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_browse.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '3ilbpixhyia0',
+          'title': '我的拼单',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/pintuan/diy/member/style1/nav_my_spell.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '9tlbcgxsyihe',
+          'title': '我的助力',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/friend_help/diy/member/style1/nav_my_help.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        },
+        {
+          'id': '27kxbgr5ljbw',
+          'title': '联系客服',
+          'imageUrl': 'https://v6.site.niucloud.com/addon/shop/diy/member/style1/nav_service.png',
+          'imgWidth': 92,
+          'imgHeight': 92,
+          'link': '',
+          'label': {
+            'control': false,
+            'text': '热门',
+            'textColor': '#FFFFFF',
+            'bgColorStart': '#F83287',
+            'bgColorEnd': '#FE3423'
+          }
+        }
+      ],
+      'swiper': {
+        'indicatorColor': 'rgba(0, 0, 0, 0.3)',
+        'indicatorActiveColor': '#FF0E0E',
+        'indicatorStyle': 'style-1',
+        'indicatorAlign': 'center'
+      }
+    }
+  ]
+};

+ 28 - 4
src/views/diy/edit.vue

@@ -205,7 +205,7 @@
 
 
 <script setup name="Index" lang="ts">
 <script setup name="Index" lang="ts">
 import useDiyStore from '@/store/modules/diy';
 import useDiyStore from '@/store/modules/diy';
-import { diyInit, addDiy, editDiy } from '@/api/diy/index';
+import { diyInit, addDiy, editDiy, LookDiy, LookMin } from '@/api/diy/index';
 import { data1, data2 } from './edit';
 import { data1, data2 } from './edit';
 import { cloneDeep } from 'lodash-es';
 import { cloneDeep } from 'lodash-es';
 const diyStore = useDiyStore();
 const diyStore = useDiyStore();
@@ -242,10 +242,31 @@ onMounted(() => {
   }
   }
   if (query.id) {
   if (query.id) {
     id.value = query.id;
     id.value = query.id;
+    LookDiy(id.value).then((res: any) => {
+      if (res.code == 200) {
+        const datas = JSON.parse(res.data.value);
+        diyStore.global = datas.global;
+        diyStore.value = datas.value;
+        diyStore.type = res.data.type;
+        diyStore.pageTitle = res.data.title;
+        // console.log(datas, '?????????');
+      }
+    });
   } else {
   } else {
-    id.value = '0';
+    id.value = null;
     diyStore.type = query.type.toString();
     diyStore.type = query.type.toString();
     diyStore.pageTitle = query.title.toString();
     diyStore.pageTitle = query.title.toString();
+    if (query.templateId) {
+      LookMin(query.templateId).then((res: any) => {
+        if (res.code == 200) {
+          const datas = JSON.parse(res.data.property);
+          diyStore.global = datas.global;
+          diyStore.value = datas.value;
+          diyStore.type = res.data.type;
+          diyStore.pageTitle = res.data.name;
+        }
+      });
+    }
   }
   }
 });
 });
 
 
@@ -266,7 +287,7 @@ const save = (type?: number) => {
   if (isRepeat.value) return;
   if (isRepeat.value) return;
   isRepeat.value = true;
   isRepeat.value = true;
 
 
-  const data = {
+  const datas = {
     id: id.value,
     id: id.value,
     page_title: diyStore.pageTitle,
     page_title: diyStore.pageTitle,
     title: diyStore.global.title,
     title: diyStore.global.title,
@@ -279,7 +300,10 @@ const save = (type?: number) => {
   };
   };
 
 
   const api = id.value ? editDiy : addDiy;
   const api = id.value ? editDiy : addDiy;
-  api(data)
+  if (id.value == null) {
+    delete datas.id;
+  }
+  api(datas)
     .then((res: any) => {
     .then((res: any) => {
       isRepeat.value = false;
       isRepeat.value = false;
       if (res.code == 200) {
       if (res.code == 200) {

+ 44 - 19
src/views/diy/list.vue

@@ -24,15 +24,22 @@
       </template>
       </template>
 
 
       <el-table v-loading="loading" border :data="dataList">
       <el-table v-loading="loading" border :data="dataList">
-        <el-table-column label="页面名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
-        <el-table-column label="所属应用" align="center" :show-overflow-tooltip="true">
-          <template #default="scope">
-            {{ scope.row.dictType }}
-          </template>
-        </el-table-column>
+        <el-table-column label="页面名称" align="center" prop="title" :show-overflow-tooltip="true" />
         <el-table-column label="页面类型" align="center" :show-overflow-tooltip="true">
         <el-table-column label="页面类型" align="center" :show-overflow-tooltip="true">
           <template #default="scope">
           <template #default="scope">
-            {{ scope.row.dictType }}
+            {{
+              scope.row.type == 1
+                ? '首页'
+                : scope.row.type == 2
+                  ? '个人中心'
+                  : scope.row.type == 3
+                    ? '商品详情'
+                    : scope.row.type == 4
+                      ? '分类'
+                      : scope.row.type == 5
+                        ? '自定义'
+                        : ''
+            }}
           </template>
           </template>
         </el-table-column>
         </el-table-column>
         <el-table-column label="状态" align="center" :show-overflow-tooltip="true">
         <el-table-column label="状态" align="center" :show-overflow-tooltip="true">
@@ -40,11 +47,6 @@
             {{ scope.row.dictType }}
             {{ scope.row.dictType }}
           </template>
           </template>
         </el-table-column>
         </el-table-column>
-        <el-table-column label="更新时间" align="center" :show-overflow-tooltip="true">
-          <template #default="scope">
-            {{ scope.row.dictType }}
-          </template>
-        </el-table-column>
         <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
         <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
           <template #default="scope">
           <template #default="scope">
             <el-tooltip content="修改" placement="top">
             <el-tooltip content="修改" placement="top">
@@ -87,7 +89,7 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import { diyList, delDiy, template } from '@/api/diy/index';
+import { diyList, delDiy, template, miniList } from '@/api/diy/index';
 import { FormInstance } from 'element-plus';
 import { FormInstance } from 'element-plus';
 import diy1 from '@/assets/images/diy/diy1.jpg';
 import diy1 from '@/assets/images/diy/diy1.jpg';
 import diy2 from '@/assets/images/diy/diy2.jpg';
 import diy2 from '@/assets/images/diy/diy2.jpg';
@@ -100,16 +102,32 @@ const loading = ref(true);
 const total = ref(0);
 const total = ref(0);
 const dialogType = ref();
 const dialogType = ref();
 const dialogList = ref<any>([
 const dialogList = ref<any>([
-  { title: '首页', diyType: 1, img: diy1 },
-  { title: '分类', diyType: 2, img: diy2 },
-  { title: '个人中心', diyType: 3, img: diy3 },
-  { title: '商品详情', diyType: 4, img: diy4 },
+  // { title: '首页', diyType: 1, img: diy1 },
+  // { title: '个人中心', diyType: 3, img: diy3 },
+  // { title: '商品详情', diyType: 4, img: diy4 },
+  // { title: '分类', diyType: 4, img: diy2 },
   { title: '自定义页面', diyType: 5, img: diy5 }
   { title: '自定义页面', diyType: 5, img: diy5 }
 ]);
 ]);
 
 
 const pageType: any = reactive({}); // 页面类型
 const pageType: any = reactive({}); // 页面类型
 const dialogVisible = ref(false);
 const dialogVisible = ref(false);
 const formRef = ref<FormInstance>();
 const formRef = ref<FormInstance>();
+
+miniList({ pageNum: 1, pageSize: 10 }).then((res) => {
+  if (res.code == 200) {
+    res.rows.forEach((item: any) => {
+      const obj = {
+        title: item.name,
+        diyType: item.type,
+        img: item.type == 1 ? diy1 : item.type == 2 ? diy3 : diy4,
+        templateId: item.id
+      };
+      // dialogList.value.unshift(obj);
+      dialogList.value.push(obj);
+    });
+  }
+});
+
 // 添加自定义页面
 // 添加自定义页面
 const formData = reactive({
 const formData = reactive({
   title: '',
   title: '',
@@ -162,7 +180,14 @@ const handleAdd = () => {
   // window.open(url.href);
   // window.open(url.href);
 };
 };
 /** 修改按钮操作 */
 /** 修改按钮操作 */
-const handleUpdate = async (row?: any) => {};
+const handleUpdate = async (row?: any) => {
+  const query = { id: row.id };
+  const url = router.resolve({
+    path: '/diy/edit',
+    query
+  });
+  window.open(url.href);
+};
 /** 删除按钮操作 */
 /** 删除按钮操作 */
 const handleDelete = async (row?: any) => {
 const handleDelete = async (row?: any) => {
   await proxy?.$modal.confirm('是否确认删除"' + row.name + '"的diy数据项?').finally(() => (loading.value = false));
   await proxy?.$modal.confirm('是否确认删除"' + row.name + '"的diy数据项?').finally(() => (loading.value = false));
@@ -187,7 +212,7 @@ const getTemplate = () => {
 
 
 const addEvent = () => {
 const addEvent = () => {
   const obj = dialogList.value.find((item: any) => item.diyType == dialogType.value);
   const obj = dialogList.value.find((item: any) => item.diyType == dialogType.value);
-  const query = { type: obj.diyType, title: obj.title };
+  const query = { type: obj.diyType, title: obj.title, templateId: obj.templateId ? obj.templateId : '' };
   const url = router.resolve({
   const url = router.resolve({
     path: '/diy/edit',
     path: '/diy/edit',
     query
     query

+ 589 - 0
src/views/diy/miniEdit.vue

@@ -0,0 +1,589 @@
+<template>
+  <div class="flex-1 diy-edit">
+    <el-header class="flex items-center h-[60px] bg-primary px-[20px]">
+      <div class="text-white cursor-pointer flex items-center" @click="goBack">
+        <el-icon size="14">
+          <ArrowLeft />
+        </el-icon>
+        <span class="pl-[5px] text-[14px]">返回</span>
+      </div>
+      <div class="text-white ml-[10px] mr-[20px] flex items-center">
+        <span class="mr-[5px] text-[rgba(255,255,255,.5)]">|</span>
+        <span class="mr-[5px] text-[14px]">正在装修:{{ diyStore.pageTitle }}</span>
+      </div>
+      <div class="flex-1"></div>
+      <el-button @click="preview()">保存并预览</el-button>
+      <el-button @click="save()">保存</el-button>
+    </el-header>
+    <div class="full-container flex flex-row flex-1 bg-page">
+      <div class="component-list w-[290px]">
+        <!-- 组件列表区域 -->
+        <el-scrollbar class="px-[10px]">
+          <el-collapse v-model="activeNames">
+            <el-collapse-item v-for="(item, key) in component" :key="key" :title="item.title" :name="key">
+              <ul class="flex flex-row flex-wrap">
+                <li
+                  v-for="(compItem, compKey) in item.list"
+                  :key="compKey"
+                  class="w-2/6 text-center cursor-pointer h-[65px]"
+                  :title="compItem.title"
+                  @click="diyStore.addComponent(compKey, compItem)"
+                >
+                  <icon v-if="compItem.icon" :name="compItem.icon" size="20px" class="inline-block mt-[3px]" />
+                  <icon v-else name="iconfont iconkaifazujian" size="20px" class="inline-block mt-[3px]" />
+                  <span class="block text-[12px] truncate">{{ compItem.title }}</span>
+                </li>
+              </ul>
+            </el-collapse-item>
+          </el-collapse>
+        </el-scrollbar>
+      </div>
+      <div class="preview-wrap flex-1 relative mt-[20px]">
+        <el-scrollbar>
+          <el-button class="page-btn absolute right-[20px]" @click="diyStore.changeCurrentIndex(-99)">页面设置</el-button>
+          <div class="diy-view-wrap w-[375px] shadow-lg mx-auto">
+            <div
+              class="preview-head bg-no-repeat bg-center bg-cover cursor-pointer h-[64px]"
+              :class="[diyStore.global.topStatusBar.style]"
+              :style="{ backgroundColor: diyStore.global.topStatusBar.bgColor }"
+              @click="diyStore.changeCurrentIndex(-99)"
+            >
+              <div v-if="diyStore.global.topStatusBar.style == 'style-1' && diyStore.global.topStatusBar.isShow" class="content-wrap">
+                <div
+                  class="title-wrap"
+                  :style="`color: ${diyStore.global.topStatusBar?.textColor || ''}; text-align: ${diyStore.global.topStatusBar?.textAlign || ''};`"
+                >
+                  {{ diyStore.global.title }}
+                </div>
+              </div>
+            </div>
+            <div class="preview-block relative">
+              <ul class="quick-action absolute text-center -right-[70px] top-[20px] w-[42px] rounded shadow-md">
+                <el-tooltip effect="light" content="上移" placement="right">
+                  <icon name="iconfont iconjiantoushang" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
+                </el-tooltip>
+                <el-tooltip effect="light" content="下移" placement="right">
+                  <icon name="iconfont iconjiantouxia" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
+                </el-tooltip>
+                <el-tooltip effect="light" content="复制" placement="right">
+                  <icon name="iconfont iconcopy-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
+                </el-tooltip>
+                <el-tooltip effect="light" content="删除" placement="right">
+                  <icon name="iconfont icondelete-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
+                </el-tooltip>
+                <el-tooltip effect="light" content="重置" placement="right">
+                  <icon name="iconfont iconloader-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
+                </el-tooltip>
+              </ul>
+
+              <!-- 组件预览渲染区域 -->
+              <iframe id="previewIframe" v-show="loadingIframe" :src="wapPreview" frameborder="0" class="preview-iframe w-[375px]"></iframe>
+            </div>
+          </div>
+        </el-scrollbar>
+      </div>
+      <div class="edit-attribute-wrap w-[400px]">
+        <!-- 编辑组件属性区域 -->
+        <el-scrollbar>
+          <el-card class="box-card" shadow="never">
+            <template #header>
+              <div class="card-header flex justify-between items-center">
+                <span class="title flex-1">{{ diyStore.currentIndex == -99 ? '页面设置' : diyStore.editComponent.componentTitle }}</span>
+                <div class="tab-wrap flex rounded-[50px] bg-gray-100 text-[14px]" v-if="diyStore.currentComponent">
+                  <span
+                    class="cursor-pointer rounded-[50px] py-[5px] px-[15px]"
+                    :class="{ 'bg-primary text-white': diyStore.editTab == 'content' }"
+                    @click="diyStore.editTab = 'content'"
+                    >内容</span
+                  >
+                  <span
+                    class="cursor-pointer rounded-[50px] py-[5px] px-[15px]"
+                    :class="{ 'bg-primary text-white': diyStore.editTab == 'style' }"
+                    @click="diyStore.editTab = 'style'"
+                    >样式</span
+                  >
+                </div>
+              </div>
+            </template>
+
+            <div class="edit-component-wrap">
+              <component
+                v-if="diyStore.currentComponent"
+                :is="modules[diyStore.currentComponent]"
+                :key="diyStore.currentIndex"
+                :value="diyStore.value[diyStore.currentIndex]"
+              >
+                <template #style>
+                  <div class="edit-attr-item-wrap">
+                    <h3 class="mb-[10px]">组件样式</h3>
+                    <el-form label-width="90px" class="px-[10px]">
+                      <template v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
+                        <el-form-item label="底部背景">
+                          <el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
+                          <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
+                          <el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
+                        </el-form-item>
+                        <div class="text-sm text-gray-400 ml-[90px] mb-[10px]">底部背景包含边距和圆角</div>
+                      </template>
+
+                      <el-form-item label="渐变角度" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
+                        <el-radio-group v-model="diyStore.editComponent.pageGradientAngle">
+                          <el-radio value="to bottom">从上到下</el-radio>
+                          <el-radio value="to right">从左到右</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+
+                      <!-- <el-form-item label="组件背景图" v-if="diyStore.editComponent.ignore.indexOf('componentBgUrl') == -1">
+                        <upload-image v-model="diyStore.editComponent.componentBgUrl" :limit="1" />
+                      </el-form-item> -->
+
+                      <el-form-item
+                        label="透明度"
+                        v-if="diyStore.editComponent.ignore.indexOf('componentBgUrl') == -1 && diyStore.editComponent.componentBgUrl"
+                      >
+                        <el-slider
+                          v-model="diyStore.editComponent.componentBgAlpha"
+                          show-input
+                          size="small"
+                          :min="0"
+                          :max="10"
+                          class="ml-[10px] diy-nav-slider"
+                        />
+                      </el-form-item>
+
+                      <el-form-item label="组件背景色" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
+                        <el-color-picker v-model="diyStore.editComponent.componentStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
+                        <icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
+                        <el-color-picker v-model="diyStore.editComponent.componentEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
+                      </el-form-item>
+
+                      <el-form-item label="渐变角度" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
+                        <el-radio-group v-model="diyStore.editComponent.componentGradientAngle">
+                          <el-radio value="to bottom">从上到下</el-radio>
+                          <el-radio value="to right">从左到右</el-radio>
+                        </el-radio-group>
+                      </el-form-item>
+
+                      <el-form-item label="上边距" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
+                        <el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="-100" class="ml-[10px] diy-nav-slider" />
+                      </el-form-item>
+                      <el-form-item label="下边距" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
+                        <el-slider
+                          v-model="diyStore.editComponent.margin.bottom"
+                          show-input
+                          size="small"
+                          class="ml-[10px] diy-nav-slider"
+                          :min="-100"
+                        />
+                      </el-form-item>
+                      <el-form-item label="左右边距" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
+                        <el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] diy-nav-slider" />
+                      </el-form-item>
+                      <el-form-item label="上圆角" v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
+                        <el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
+                      </el-form-item>
+                      <el-form-item label="下圆角" v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
+                        <el-slider
+                          v-model="diyStore.editComponent.bottomRounded"
+                          show-input
+                          size="small"
+                          class="ml-[10px] diy-nav-slider"
+                          :max="100"
+                        />
+                      </el-form-item>
+                    </el-form>
+                  </div>
+                </template>
+              </component>
+            </div>
+          </el-card>
+        </el-scrollbar>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup name="Index" lang="ts">
+import useDiyStore from '@/store/modules/diy';
+import { LookMin, addMin, editMin } from '@/api/diy/index';
+import { data1, data2, data3, data4 } from './edit';
+import { cloneDeep } from 'lodash-es';
+const diyStore = useDiyStore();
+const route = useRoute();
+const id = ref<any>(null);
+const query = route.query;
+const component = ref<any>([]);
+const componentType: string[] = reactive([]);
+const activeNames = ref(componentType);
+const loadingIframe = ref(false); // 加载iframe
+const wapPreview = ref<any>('');
+const timeIframe = ref(0); // iframe打开时间
+const difference = ref(0); // 检测页面加载差异,小于1000毫秒,则配置wap端域名
+const isRepeat = ref(false);
+
+onMounted(() => {
+  wapPreview.value = data1.domain_url.wap_url + data1.page + '?mode=decorate';
+  component.value = data1.component;
+  for (const type in component.value) {
+    componentType.push(type);
+    for (const key in component.value[type].list) {
+      const com = cloneDeep(component.value[type].list[key]);
+      com.id = diyStore.generateRandom();
+      com.componentName = key;
+      com.componentTitle = com.title;
+      Object.assign(com, com.value);
+      delete com.name;
+      delete com.title;
+      delete com.value;
+      delete com.type;
+      delete com.icon;
+      diyStore.components.push(com);
+    }
+  }
+  if (query.id) {
+    id.value = query.id;
+    LookMin(id.value).then((res: any) => {
+      if (res.code == 200) {
+        const datas = JSON.parse(res.data.property);
+        diyStore.global = datas.global;
+        diyStore.value = datas.value;
+        diyStore.type = res.data.type;
+        diyStore.pageTitle = res.data.name;
+      }
+    });
+  } else {
+    id.value = null;
+    diyStore.type = query.type.toString();
+    diyStore.pageTitle = query.title.toString();
+    // 首页模板1
+    // diyStore.global = data3.global;
+    // diyStore.value = data3.value;
+    // 个人中心模板
+    // diyStore.global = data4.global;
+    // diyStore.value = data4.value;
+    // 商品详情模板
+    // diyStore.global = data2.shop_goods_detail_style1.data.global;
+    // diyStore.value = data2.shop_goods_detail_style1.data.value;
+  }
+});
+
+// 返回上一页
+const goBack = () => {
+  location.href = `${location.origin}/diy/list`;
+};
+
+// 预览
+const preview = () => {};
+
+// 保存
+const save = (type?: number) => {
+  if (!diyStore.verify()) {
+    return;
+  }
+
+  if (isRepeat.value) return;
+  isRepeat.value = true;
+
+  const datas = {
+    id: id.value,
+    name: diyStore.pageTitle,
+    type: diyStore.type,
+    property: JSON.stringify({
+      global: toRaw(diyStore.global),
+      value: toRaw(diyStore.value)
+    })
+  };
+
+  console.log(datas, '??????????');
+
+  const api = id.value ? editMin : addMin;
+  if (id.value == null) {
+    delete datas.id;
+  }
+
+  api(datas)
+    .then((res: any) => {
+      isRepeat.value = false;
+      if (res.code == 200) {
+        ElMessage({
+          message: '保存成功~',
+          type: 'success'
+        });
+        if (type == 1) {
+          window.open('/diy/diy?id=' + res.data.id);
+        }
+      }
+    })
+    .catch(() => {
+      isRepeat.value = false;
+    });
+};
+
+// 动态加载后台自定义组件编辑
+const modulesFiles = import.meta.glob('./components/*.vue', { eager: true });
+const addonModulesFiles = import.meta.glob('@/views/diy/components/*.vue', { eager: true });
+addonModulesFiles && Object.assign(modulesFiles, addonModulesFiles);
+const modules = {};
+for (const [key, value] of Object.entries(modulesFiles)) {
+  const moduleName = key.split('/').pop();
+  const name = moduleName.split('.')[0];
+  modules[name] = (value as any).default;
+}
+
+// 监听组件数据 uni-app端
+window.addEventListener(
+  'message',
+  (event) => {
+    try {
+      let data = {
+        type: '',
+        index: null,
+        component: null,
+        global: null,
+        value: null
+      };
+      if (typeof event.data == 'string') {
+        data = JSON.parse(event.data);
+      } else if (typeof event.data == 'object') {
+        data = event.data;
+      }
+      if (!data.type) return;
+
+      switch (data.type) {
+        case 'appOnLaunch':
+        case 'appOnReady':
+          // // uni-app 加载完成
+          loadingIframe.value = true;
+          const loadTime = new Date().getTime();
+          difference.value = loadTime - timeIframe.value;
+          break;
+        case 'init':
+          // 初始化,与uniapp建立连接传输数据
+          diyStore.load = true;
+          diyStore.postMessage();
+          break;
+        case 'change':
+          // 切换
+          diyStore.changeCurrentIndex(data.index, data.component);
+          break;
+        case 'data':
+          // 传数据
+          diyStore.changeCurrentIndex(data.index, data.component);
+          diyStore.global = data.global;
+          diyStore.value = data.value;
+          break;
+      }
+    } catch (e) {
+      console.log('diy edit 后台接受数据错误', e);
+    }
+  },
+  false
+);
+
+// 全局监听自定义数据变化
+watch(
+  () => diyStore,
+  (newValue, oldValue) => {
+    const data = {
+      id: newValue.id,
+      name: newValue.name,
+      pageTitle: newValue.pageTitle,
+      title: newValue.global.title,
+      value: JSON.stringify({
+        global: toRaw(newValue.global),
+        value: toRaw(newValue.value)
+      })
+    };
+
+    diyStore.postMessage();
+  },
+  { deep: true }
+);
+</script>
+
+<style lang="scss">
+.diy-edit {
+  background-color: #f2f2f2;
+}
+.el-collapse-item__wrap {
+  border-bottom: none;
+}
+
+.el-collapse-item__content {
+  padding-bottom: 0;
+}
+
+.el-collapse-item__header {
+  font-size: var(--el-font-size-base);
+}
+
+.display-block {
+  .el-form-item__content {
+    display: block;
+  }
+}
+
+.edit-component-wrap {
+  .content-wrap,
+  .style-wrap {
+    .edit-attr-item-wrap {
+      border-top: 2px solid var(--el-color-info-light-8);
+      padding-top: 20px;
+
+      &:first-of-type {
+        border-top: none;
+        padding-top: 0;
+      }
+    }
+  }
+}
+
+.diy-nav-slider {
+  .el-slider__input {
+    width: 100px;
+  }
+}
+</style>
+<style lang="scss" scoped>
+.full-container {
+  height: calc(100vh - 60px);
+}
+
+.preview-iframe {
+  height: calc(100vh - 160px);
+}
+
+.component-list {
+  background: var(--el-bg-color);
+}
+
+.component-list ul li {
+  &:not(.disabled):hover {
+    color: var(--el-color-primary);
+    background: var(--el-color-primary-light-9);
+  }
+}
+
+.diy-view-wrap {
+  background: var(--el-bg-color-page);
+}
+
+.diy-view-wrap .preview-head {
+  background-image: url(@/assets/images/diy/diy_preview_head.png);
+  background-color: var(--el-bg-color);
+}
+
+.quick-action {
+  background: var(--el-bg-color);
+}
+
+.edit-attribute-wrap {
+  background: var(--el-bg-color);
+}
+
+.edit-attribute-wrap .box-card {
+  border: none;
+}
+
+.diy-view-wrap .preview-head {
+  padding: 28px 15px 0;
+
+  .content-wrap {
+    height: 30px;
+  }
+
+  &.style-1 {
+    .content-wrap {
+      .title-wrap {
+        height: 30px;
+        line-height: 30px;
+      }
+    }
+  }
+
+  &.style-2 {
+    .content-wrap {
+      .title-wrap {
+        display: flex;
+        align-items: center;
+
+        > div {
+          height: 30px;
+          line-height: 30px;
+          max-width: 150px;
+          font-size: 14px;
+
+          &:last-child {
+            overflow: hidden; //超出的文本隐藏
+            text-overflow: ellipsis; //用省略号显示
+            white-space: nowrap; //不换行
+            flex: 1;
+            max-width: 200px;
+          }
+        }
+      }
+    }
+  }
+
+  &.style-3 {
+    .content-wrap {
+      display: flex;
+      align-items: center;
+
+      .title-wrap {
+        height: 30px;
+        max-width: 85px;
+        margin-right: 5px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+
+      .search {
+        flex: 1;
+        padding-right: 10px;
+        padding-left: 31px;
+        position: relative;
+        background-color: #fff;
+        text-align: left;
+        border-radius: 30px;
+        height: 30px;
+        line-height: 30px;
+        border: 1px solid #eeeeee;
+        color: rgb(102, 102, 102);
+        display: flex;
+        align-items: center;
+        margin-right: 105px;
+        overflow: hidden;
+        box-sizing: border-box;
+
+        span {
+          overflow: hidden; //超出的文本隐藏
+          text-overflow: ellipsis; //用省略号显示
+          white-space: nowrap; //不换行
+        }
+
+        .iconfont {
+          color: #909399;
+          font-size: 16px;
+          margin-right: 5px;
+        }
+      }
+    }
+  }
+
+  &.style-4 {
+    .content-wrap {
+      display: flex;
+      align-items: center;
+
+      .title-wrap {
+        flex: none;
+        margin: 0 5px;
+        max-width: 180px;
+        font-size: 14px;
+      }
+    }
+  }
+}
+</style>

+ 270 - 0
src/views/diy/miniTemplate.vue

@@ -0,0 +1,270 @@
+<template>
+  <div class="p-2">
+    <div class="head-card">
+      <el-card shadow="hover">
+        <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+          <el-form-item label="模板名称">
+            <el-input v-model="queryParams.title" placeholder="请输入模板名称" clearable @keyup.enter="handleQuery" />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+            <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+
+    <el-card shadow="hover">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd">添加模板</el-button>
+          </el-col>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="dataList">
+        <el-table-column label="模板名称" align="center" prop="name" :show-overflow-tooltip="true" />
+        <el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
+            </el-tooltip>
+            <el-tooltip content="删除" placement="top">
+              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
+            </el-tooltip>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination v-show="total > 0" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
+    </el-card>
+
+    <!--添加页面-->
+    <el-dialog v-model="dialogVisible" title="创建新模板" width="1122px">
+      <div class="card-container">
+        <div
+          v-for="(item, index) in dialogList"
+          @click="onDialog(item)"
+          :key="index"
+          class="card-item"
+          :class="{ active: dialogType === item.diyType }"
+        >
+          <div class="card-image">
+            <img :src="item.img" alt="图片" />
+          </div>
+          <div class="card-text">{{ item.title }}</div>
+        </div>
+      </div>
+
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="addEvent()">确认</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { miniList, delMin, template } from '@/api/diy/index';
+import { FormInstance } from 'element-plus';
+import diy1 from '@/assets/images/diy/diy1.jpg';
+import diy2 from '@/assets/images/diy/diy2.jpg';
+import diy3 from '@/assets/images/diy/diy3.jpg';
+import diy4 from '@/assets/images/diy/diy4.png';
+import diy5 from '@/assets/images/diy/diy5.jpg';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const dataList = ref<any[]>([]);
+const loading = ref(true);
+const total = ref(0);
+const dialogType = ref();
+const dialogList = ref<any>([
+  { title: '首页模板', diyType: 1, img: diy1 },
+  { title: '个人中心模板', diyType: 2, img: diy3 },
+  { title: '商品详情模板', diyType: 3, img: diy4 }
+]);
+
+const pageType: any = reactive({}); // 页面类型
+const dialogVisible = ref(false);
+const formRef = ref<FormInstance>();
+// 添加自定义页面
+const formData = reactive({
+  title: '',
+  type: ''
+});
+// 表单验证规则
+const formRules = computed(() => {
+  return {
+    title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
+    type: [{ required: true, message: '请选择页面类型', trigger: 'blur' }]
+  };
+});
+
+const queryParams = ref<any>({
+  pageNum: 1,
+  pageSize: 10,
+  title: '',
+  addon_name: '',
+  type: ''
+});
+
+/** 查询字典类型列表 */
+const getList = () => {
+  loading.value = true;
+  miniList(queryParams.value).then((res) => {
+    if (res.code == 200) {
+      dataList.value = res.rows;
+      total.value = res.total;
+      loading.value = false;
+    }
+  });
+};
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+/** 重置按钮操作 */
+const resetQuery = () => {
+  handleQuery();
+};
+/** 新增按钮操作 */
+const router = useRouter();
+const handleAdd = () => {
+  dialogVisible.value = true;
+  // const url = router.resolve({
+  //   path: '/diy/edit',
+  //   query: {}
+  // });
+  // window.open(url.href);
+};
+/** 修改按钮操作 */
+const handleUpdate = async (row?: any) => {
+  const query = { id: row.id };
+  const url = router.resolve({
+    path: '/diy/miniEdit',
+    query
+  });
+  window.open(url.href);
+};
+/** 删除按钮操作 */
+const handleDelete = async (row?: any) => {
+  await proxy?.$modal.confirm('是否确认删除"' + row.name + '"的diy数据项?').finally(() => (loading.value = false));
+  await delMin(row.id);
+  proxy?.$modal.msgSuccess('删除成功');
+  getList();
+};
+
+const getTemplate = () => {
+  template({ mode: '', addon: '' }).then((res) => {
+    if (res.code == 200) {
+      for (const key in pageType) {
+        delete pageType[key];
+      }
+
+      for (const key in res.data) {
+        pageType[key] = res.data[key];
+      }
+    }
+  });
+};
+
+const addEvent = () => {
+  const obj = dialogList.value.find((item: any) => item.diyType == dialogType.value);
+  const query = { type: obj.diyType, title: obj.title };
+  const url = router.resolve({
+    path: '/diy/miniEdit',
+    query
+  });
+  window.open(url.href);
+  dialogVisible.value = false;
+};
+
+// const addEvent = async (formEl: FormInstance | undefined) => {
+//   if (!formEl) return;
+
+//   await formEl.validate(async (valid) => {
+//     if (valid) {
+//       const query = { type: formData.type, title: formData.title };
+//       const url = router.resolve({
+//         path: '/diy/edit',
+//         query
+//       });
+//       window.open(url.href);
+//       dialogVisible.value = false;
+//       formData.title = '';
+//       formData.type = '';
+//     }
+//   });
+// };
+
+const onDialog = (item: any) => {
+  dialogType.value = item.diyType;
+};
+
+onMounted(() => {
+  getList();
+  getTemplate();
+});
+</script>
+
+<style lang="scss" scoped>
+.head-card {
+  margin-bottom: 20px;
+  :deep(.el-card__body) {
+    padding-bottom: 0px !important;
+  }
+}
+
+.card-container {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 0 15px;
+  width: 1060px;
+  .card-item {
+    width: 200px;
+    height: 390px;
+    padding: 5px;
+    border-radius: 8px;
+    border: 1px solid #e5e7eb;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    position: relative;
+
+    &:hover {
+      border-color: #b0b0b0;
+    }
+
+    &.active {
+      border-color: #409eff;
+      background-color: #ecf5ff;
+    }
+    .card-image {
+      width: 190px;
+      height: 340px;
+      overflow: hidden;
+      border-radius: 4px;
+
+      img {
+        width: 100%;
+        height: 100%;
+        object-fit: cover;
+      }
+    }
+    .card-text {
+      width: 190px;
+      bottom: 0;
+      left: 0;
+      font-size: 14px;
+      color: #333;
+      text-align: center;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      text-align: center;
+      margin-top: 20px;
+    }
+  }
+}
+</style>