Files
lucky_shop/components-diy/diy-group.vue

469 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view data-component-name="diy-group" class="diy-group">
<view v-for="(item, index) in diyDataArray" :key="index" :style="item.pageStyle">
<view v-if="addonIsExist.store && item.componentName == 'StoreShow'">
<!-- 门店展示 -->
<diy-store :value="item"></diy-store>
</view>
<template v-if="item.componentName == 'Kefu'">
<!-- 客服按钮 -->
<diy-kefu :value="item"></diy-kefu>
</template>
<template v-if="item.componentName == 'Form'">
<!-- 表单组件 -->
<diy-form :value="item"></diy-form>
</template>
<template v-if="addonIsExist.store && item.componentName == 'StoreLabel'">
<!-- 门店标签 -->
<diy-store-label :value="item"></diy-store-label>
</template>
<template v-if="item.componentName == 'Picture'">
<!-- 单图组组件 -->
<diy-picture :value="item"></diy-picture>
</template>
<template v-if="item.componentName == 'Listmenu'">
<!-- 列表按钮组件 -->
<diy-listmenu :value="item"></diy-listmenu>
</template>
<template v-if="item.componentName == 'Text'">
<!-- 文本 -->
<diy-text :value="item"></diy-text>
</template>
<template v-if="item.componentName == 'Notice'">
<!-- 公告 -->
<diy-notice :value="item"></diy-notice>
</template>
<template v-if="item.componentName == 'GraphicNav'">
<!-- 图文导航 -->
<diy-graphic-nav :value="item"></diy-graphic-nav>
</template>
<template v-if="item.componentName == 'ImageAds'">
<!-- 图片广告 -->
<diy-img-ads :value="item"></diy-img-ads>
</template>
<template v-if="item.componentName == 'Search'">
<!-- 搜索 -->
<diy-search :value="item" :topNavColor="topNavColor" :global="diyGlobalData.global"
:haveTopCategory="haveTopCategory" :followOfficialAccount="followOfficialAccount"></diy-search>
</template>
<template v-if="item.componentName == 'RichText'">
<!-- 富文本 -->
<diy-rich-text :value="item"></diy-rich-text>
</template>
<template v-if="item.componentName == 'HorzLine'">
<!-- 辅助线 -->
<diy-horz-line :value="item"></diy-horz-line>
</template>
<template v-if="item.componentName == 'HorzBlank'">
<!-- 辅助空白 -->
<diy-horz-blank :value="item"></diy-horz-blank>
</template>
<template v-if="item.componentName == 'Coupon' && addonIsExist.coupon">
<!-- 优惠券 -->
<diy-coupon :value="item"></diy-coupon>
</template>
<template v-if="item.componentName == 'GoodsList'">
<!-- 商品列表 -->
<diy-goods-list :value="item"></diy-goods-list>
</template>
<template v-if="item.componentName == 'ManyGoodsList'">
<!-- 多商品组 -->
<diy-many-goods-list :value="item" :global="diyGlobalData.global"
:scrollTop="scrollTop"></diy-many-goods-list>
</template>
<template v-if="item.componentName == 'RubikCube'">
<!-- 魔方、橱窗 -->
<diy-rubik-cube :value="item"></diy-rubik-cube>
</template>
<template v-if="item.componentName == 'Video'">
<!-- 视频 -->
<diy-video :value="item"></diy-video>
</template>
<template v-if="item.componentName == 'Seckill' && addonIsExist.seckill">
<!-- 秒杀 -->
<diy-seckill :value="item"></diy-seckill>
</template>
<template v-if="item.componentName == 'Pintuan' && addonIsExist.pintuan">
<!-- 拼团 -->
<diy-pintuan :value="item"></diy-pintuan>
</template>
<template v-if="item.componentName == 'Groupbuy' && addonIsExist.groupbuy">
<!-- 团购 -->
<diy-groupbuy :value="item"></diy-groupbuy>
</template>
<!-- 拼团返利 -->
<template v-if="item.componentName == 'Pinfan' && addonIsExist.pinfan">
<diy-pinfan :value="item"></diy-pinfan>
</template>
<template v-if="item.componentName == 'Bargain' && addonIsExist.bargain">
<!-- 砍价 -->
<diy-bargain :value="item"></diy-bargain>
</template>
<template v-if="item.componentName == 'Presale' && addonIsExist.bargain">
<!-- 预售 -->
<diy-presale :value="item"></diy-presale>
</template>
<template v-if="item.componentName == 'Notes' && addonIsExist.notes">
<!-- 店铺笔记 -->
<diy-notes :value="item"></diy-notes>
</template>
<template v-if="item.componentName == 'FloatBtn'">
<!-- 浮动按钮 -->
<diy-float-btn :value="item"></diy-float-btn>
</template>
<template v-if="item.componentName == 'LiveInfo'">
<!-- 小程序直播 -->
<!-- #ifdef MP-WEIXIN -->
<diy-live :value="item"></diy-live>
<!-- #endif -->
</template>
<template v-if="item.componentName == 'FenxiaoGoodsList'">
<!-- 分销商品 -->
<diy-fenxiao-goods-list :value="item"></diy-fenxiao-goods-list>
</template>
<template v-if="item.componentName == 'GoodsRecommend'">
<!-- 商品推荐 -->
<diy-goods-recommend :value="item"></diy-goods-recommend>
</template>
<template v-if="item.componentName == 'GoodsBrand'">
<!-- 商品品牌 -->
<diy-goods-brand :value="item"></diy-goods-brand>
</template>
<template v-if="item.componentName == 'Article'">
<!-- 文章 -->
<diy-article :value="item"></diy-article>
</template>
<template v-if="item.componentName == 'MerchList'">
<!-- 商户列表 -->
<diy-merch-list :value="item"></diy-merch-list>
</template>
<template v-if="item.componentName == 'MemberInfo'">
<!-- 自定义会员中心——会员信息 -->
<diy-member-info ref="diyMemberIndex" :value="item" :global="diyGlobalData.global"></diy-member-info>
</template>
<template v-if="item.componentName == 'MemberMyOrder'">
<!-- 自定义会员中心——我的订单 -->
<diy-member-my-order ref="diyMemberMyOrder" :value="item"></diy-member-my-order>
</template>
<template v-if="item.componentName == 'QuickNav'">
<!-- 快捷导航 -->
<diy-quick-nav :value="item"></diy-quick-nav>
</template>
<template v-if="item.componentName == 'PaymentQrcode'">
<!-- 付款码 -->
<diy-payment-qrcode :value="item"></diy-payment-qrcode>
</template>
<template v-if="item.componentName == 'HotArea'">
<!-- 热区 -->
<diy-hot-area :value="item"></diy-hot-area>
</template>
<template v-if="item.componentName == 'FollowOfficialAccount'">
<!-- 关注公众号 -->
<diy-follow-official-account :value="item"></diy-follow-official-account>
</template>
<template v-if="item.componentName == 'Map'">
<!-- 地图组件 -->
<diy-map :value="item"></diy-map>
</template>
<template v-if="item.componentName == 'Audio'">
<!-- 音频 -->
<diy-audio :value="item"></diy-audio>
</template>
<template v-if="item.componentName == 'ImageNav'">
<!-- 图片导航 -->
<diy-image-nav :value="item"></diy-image-nav>
</template>
<template v-if="item.componentName == 'Digit'">
<!-- 数字 -->
<diy-digit :value="item"></diy-digit>
</template>
<template v-if="item.componentName == 'VideoList'">
<!-- 视频列表 -->
<diy-video-list :value="item"></diy-video-list>
</template>
<template v-if="item.componentName == 'BottomNav'">
<!-- 底部导航 -->
<diy-bottom-nav :value="item"></diy-bottom-nav>
</template>
<template v-if="item.componentName == 'CategoryItem'">
<!-- 分类项 -->
<diy-category-item :value="item"></diy-category-item>
</template>
<template v-if="item.componentName == 'Category'">
<!-- 分类 -->
<diy-category :value="item"></diy-category>
</template>
<template v-if="item.componentName == 'Icon'">
<!-- 图标 -->
<diy-icon :value="item"></diy-icon>
</template>
<template v-if="item.componentName == 'Tab'">
<!-- Tab 组件 -->
<diy-tab :value="item" :diyGlobal="diyGlobalData"></diy-tab>
</template>
<template v-if="['ChannelList', 'WechatChannel'].includes(item.componentName)">
<!-- 视频号列表 -->
<diy-channel-list :value="item"></diy-channel-list>
</template>
<!-- ✅ 我的邀请码 / 推荐码(商家 DIY 自由放置:
1) 严格匹配:后端注册的 5 个常见名字
2) 宽松匹配:componentName 包含 Recommend / Invite 关键字(不区分大小写)—— 解决后端注册名和前端数组不一致导致的"加了组件但页面不显示"问题
后端只要把组件注册成任意含 Recommend 或 Invite 关键字的名字就能渲染出来,避免前端硬编码数组漏匹配 -->
<template v-if="(function(cn){
if (!cn) return false;
var s = String(cn).toLowerCase();
// 严格匹配
if (['MyInviteCode','RecommendCode','Recommend','InviteCode','RecommendCodeDiy'].indexOf(cn) !== -1) return true;
// 宽松匹配:含 recommend / invite 关键字
if (s.indexOf('recommend') !== -1 || s.indexOf('invite') !== -1) return true;
return false;
})(item.componentName)">
<components-recommend-diy :value="item"></components-recommend-diy>
</template>
<!-- 自定义扩展组件 -->
<diy-comp-extend :value="item"></diy-comp-extend>
</view>
</view>
</template>
<script>
// 组件组展示
import DiyMinx from './minx.js'
// ✅ 显式 import 我的邀请码 DIY 组件(同级文件,相对路径引入,不依赖 @ 别名)
import ComponentsRecommendDiy from './components-recommend-diy.vue'
export default {
name: 'diy-group',
components: {
// ✅ 显式注册:避免 easycom 没配置此目录时导致 "Unknown custom element"
ComponentsRecommendDiy
},
props: {
diyData: {
type: Object
},
scrollTop: {
type: [String, Number],
default: '0'
},
haveTopCategory: {
type: Boolean
},
followOfficialAccount: {
type: Object
},
},
mixins: [DiyMinx],
data() {
return {
diyGlobalData: this.diyData ? this.$util.deepClone(this.diyData) : null,
processedData: null
};
},
watch: {
diyData: {
handler() {
this.diyGlobalData = this.diyData ? this.$util.deepClone(this.diyData) : null;
this.processData();
this._notifyLoaded();
},
deep: true
}
},
created() {
console.log('[DIY-GROUP][created] hasDiyData=', !!this.diyData, 'valueLen=', this.diyData && this.diyData.value && this.diyData.value.length);
this.processData();
},
mounted() {
console.log('[DIY-GROUP][mounted] hasDiyData=', !!this.diyData, 'valueLen=', this.diyData && this.diyData.value && this.diyData.value.length);
if (this.diyData && this.diyData.value) {
this._notifyLoaded();
}
},
computed: {
topNavColor() {
if (!this.diyData?.global) return '';
const { topNavBg, topNavColor } = this.diyData.global;
if (topNavBg) {
return this.scrollTop > 20 ? topNavColor : 'transparent';
}
return topNavColor;
},
diyDataArray() {
if (!this.processedData) {
this.processData();
}
const showModuleData = this.$store.state.diyGroupShowModule
? JSON.parse(this.$store.state.diyGroupShowModule)
: null;
// ✅ 调试日志:showModuleData 白名单如果存在,会严格过滤,推荐码组件没加进白名单就会被过滤掉 → 控制台能直接看到
try {
if (showModuleData && showModuleData.length) {
console.log('[DIY-GROUP][diyDataArray] showModuleData 白名单 = ', JSON.stringify(showModuleData));
var hasRecommendInWhite = false;
showModuleData.forEach(function(n){
var s = String(n || '').toLowerCase();
if (s.indexOf('recommend') !== -1 || s.indexOf('invite') !== -1) hasRecommendInWhite = true;
});
if (!hasRecommendInWhite) {
console.warn('[DIY-GROUP][diyDataArray] ⚠️ 白名单 showModuleData 里没有推荐码/邀请码组件名,组件会被过滤掉不显示!请在后台 DIY 编辑器里的"显示模块"中勾选上该组件');
}
}
} catch (e) {}
if (!showModuleData || !showModuleData.length) {
return this.processedData || [];
}
if (showModuleData.includes('null')) {
return [];
}
// ✅ 关键修复:白名单过滤时,对推荐码组件也做宽松匹配(白名单里是 RecommendCode 但后端是 Recommend 也能过)
// 之前严格 includes(item.componentName) 会漏掉大小写/命名不一致的情况
var recKeys = ['myinvitecode','recommendcode','recommend','invitecode','recommendcodediy'];
return (this.processedData || []).filter(item => {
// 1) 严格命中白名单
if (showModuleData.includes(item.componentName)) return true;
// 2) 推荐码组件宽松命中:item 是推荐码类型 && 白名单里有任意推荐码关键字
var itemName = String(item.componentName || '').toLowerCase();
var isRecommendItem = (recKeys.indexOf(itemName) !== -1) || itemName.indexOf('recommend') !== -1 || itemName.indexOf('invite') !== -1;
if (isRecommendItem) {
var whiteHasRecommend = false;
showModuleData.forEach(function(n){
var s = String(n || '').toLowerCase();
if (recKeys.indexOf(s) !== -1 || s.indexOf('recommend') !== -1 || s.indexOf('invite') !== -1) whiteHasRecommend = true;
});
if (whiteHasRecommend) return true;
}
return false;
});
}
},
methods: {
_notifyLoaded() {
console.log('[DIY-GROUP][_notifyLoaded] enter, will emit loaded in 300ms');
if (this._loadedTimer) clearTimeout(this._loadedTimer);
this._loadedTimer = setTimeout(() => {
console.log('[DIY-GROUP][_notifyLoaded] emit loaded');
this.$emit('loaded');
}, 300);
},
processData() {
if (!this.diyGlobalData || !this.diyGlobalData.value) {
this.processedData = [];
return;
}
// ✅ 调试日志:后台保存组件后,用户在控制台能看到 ALL componentName 列表
// 方便定位:"后端加了组件但前端不显示" → 要么 componentName 没匹配,要么 showModuleData 过滤掉了
try {
const names = this.diyGlobalData.value.map(function(it){ return it && it.componentName ? it.componentName : '(no name)'; });
console.log('[DIY-GROUP][processData] 所有DIY组件名列表 = ', JSON.stringify(names));
// 进一步打印哪些是推荐码相关的
var matched = [];
var recommendKeys = ['myinvitecode','recommendcode','recommend','invitecode','recommendcodediy','recommend','invite'];
this.diyGlobalData.value.forEach(function(it, idx){
if (!it || !it.componentName) return;
var s = String(it.componentName).toLowerCase();
if (recommendKeys.indexOf(s) !== -1 || s.indexOf('recommend') !== -1 || s.indexOf('invite') !== -1) {
matched.push('idx=' + idx + ', name=' + it.componentName);
}
});
if (matched.length) console.log('[DIY-GROUP][processData] 命中推荐码/邀请码组件 = ', matched.join('; '));
} catch (e) {}
this.processedData = this.diyGlobalData.value.map((item, index) => {
const newItem = this.$util.deepClone(item);
newItem.pageStyle = '';
newItem.moduleIndex = this.diyData.tabIndex !== undefined
? `${this.diyData.tabIndex}-${index + 1}`
: index + 1;
if (newItem.componentName !== 'Search' || newItem.positionWay !== 'fixed') {
newItem.pageStyle = `background-color:${newItem.pageBgColor};`;
if (newItem.margin) {
newItem.pageStyle += `padding-top:${newItem.margin.top * 2}rpx;`;
newItem.pageStyle += `padding-bottom:${newItem.margin.bottom * 2}rpx;`;
newItem.pageStyle += `padding-right:${newItem.margin.both * 2}rpx;`;
newItem.pageStyle += `padding-left:${newItem.margin.both * 2}rpx;`;
}
}
return newItem;
});
}
}
};
</script>
<style lang="scss">
.diy-group {
width: 100%;
}
</style>