策略: 微信小程序前端采用"专属 DIY 组件"模式实现推荐入驻主页,
不写 4 个独立 .vue 页面,而是在 components-diy/ 下新增 6 个动态数据组件,
商家在"自定义页面"装修面板里自由拖拽组合。组件 mounted 后自动 ajax
拉 /recommend/api/home/homeSummary 真实数据。
新增:
1. 6 个 vue 组件
- diy-recommend-code 推荐码展示 + 复制 + 分享链接
- diy-recommend-balance 可提现余额 / 待结算 / 累计收益 + 考察期剩余天数
- diy-recommend-stat 累计推荐 / 已入驻 / 累计收益 3 个数字
- diy-recommend-records 最近 3 条推荐(动态)
- diy-recommend-rules 奖励规则 4 条(API 推,可后台覆写)
- diy-recommend-action 立即提现 + 提现记录 + 入驻申请 三按钮
2. 公共 mixin — common/js/recommend-diy-data.js
- fetchRecommendInfo() ajax 拉 homeSummary(去抖 10s)
- computed: balance / code / probation / statistics / recentRecords / rewardRules
- formatMoney() 数字本地化
- 失败/未登录时 recommendInfo = null,模板显示占位
3. pages.json
- easycom 加规则 "diy-recommend-*" → components-diy/diy-recommend-$1.vue
- 已有 autoscan=true 自动发现;新增条目保证 builds 稳定
4. 语言包
- lang/zh-cn/components-diy/diy-recommend.js
- lang/en-us/components-diy/diy-recommend.js
5. 验证脚本
- scripts/verify_diy_recommend.js — 6 文件三段式校验
技术细节:
- 所有 vue 文件模板里 data-component-name 与 easycom 名字强一致
- 6 组件之间互不依赖,可任意组合到任意 Diy 页面
- API 数据通过 mixin 共享,组件不重复拉取
- 占位/loading/error 三态完整
- 大部分样式沿用项目既有 home-grown SCSS 写法,不引入新依赖
- bundle 体积增量 < 30KB
i18n-check.js 通过:
zh-cn: 224 files / 2678 keys
en-us: 224 files / 2678 keys
diff: 0 ✅
未做(后续可选):
- 4 个真正 .vue 页面(此 PR 不要,改用 DIY)
- getMyQrcode 真实二维码生成
- 提现账户管理 UI
168 lines
5.0 KiB
Vue
168 lines
5.0 KiB
Vue
<template>
|
|
<view data-component-name="diy-recommend-code" class="diy-recommend-code" :style="warpCss">
|
|
<!-- 标题 -->
|
|
<view class="title-line">
|
|
<view class="icon iconfont icon-recommend-prize"></view>
|
|
<text class="title">{{ $lang('components-diy.diy-recommend-code.myCode') }}</text>
|
|
</view>
|
|
|
|
<!-- 卡片 -->
|
|
<view class="code-card" v-if="code.code">
|
|
<view class="code-text" @tap="copyCode">{{ code.code }}</view>
|
|
<view class="copy-btn" @tap="copyCode">
|
|
<text class="iconfont icon-copy"></text>
|
|
<text>{{ $lang('components-diy.diy-recommend-code.copy') }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="code-card placeholder" v-else>
|
|
<text class="placeholder-text">{{ recommendError || $lang('components-diy.diy-recommend-code.loading') }}</text>
|
|
</view>
|
|
|
|
<!-- 复制 toast -->
|
|
<view v-if="copyToast" class="copy-toast">
|
|
{{ $lang('components-diy.diy-recommend-code.copySuccess') }}
|
|
</view>
|
|
|
|
<!-- 分享链接区 -->
|
|
<view class="share-bar" v-if="code.share_link">
|
|
<text class="iconfont icon-share"></text>
|
|
<text class="share-tip">{{ $lang('components-diy.diy-recommend-code.shareTip') }}</text>
|
|
<view class="share-link-card" @tap="copyShareLink">
|
|
<text class="link-text">{{ code.share_link }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import recommendData from '@/common/js/recommend-diy-data.js';
|
|
|
|
export default {
|
|
name: 'diy-recommend-code',
|
|
mixins: [recommendData],
|
|
data() {
|
|
return {
|
|
copyToast: false,
|
|
_toastTimer: null,
|
|
};
|
|
},
|
|
computed: {
|
|
warpCss() {
|
|
return {
|
|
padding: (this.value && this.value.paddingTop || 16) + 'rpx ' +
|
|
(this.value && this.value.paddingLeft || 24) + 'rpx',
|
|
backgroundColor: (this.value && this.value.componentBgColor) || 'transparent',
|
|
};
|
|
},
|
|
},
|
|
methods: {
|
|
copyCode() {
|
|
if (!this.code.code) return;
|
|
uni.setClipboardData({
|
|
data: this.code.code,
|
|
success: () => this.showCopyToast(),
|
|
});
|
|
},
|
|
copyShareLink() {
|
|
if (!this.code.share_link) return;
|
|
uni.setClipboardData({
|
|
data: this.code.share_link,
|
|
success: () => this.showCopyToast(),
|
|
});
|
|
},
|
|
showCopyToast() {
|
|
this.copyToast = true;
|
|
if (this._toastTimer) clearTimeout(this._toastTimer);
|
|
this._toastTimer = setTimeout(() => { this.copyToast = false; }, 1500);
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.diy-recommend-code {
|
|
.title-line {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 16rpx;
|
|
.icon {
|
|
font-size: 32rpx;
|
|
color: #ff9800;
|
|
margin-right: 12rpx;
|
|
}
|
|
.title {
|
|
font-size: 30rpx;
|
|
font-weight: 600;
|
|
color: #333;
|
|
}
|
|
}
|
|
.code-card {
|
|
background: linear-gradient(135deg, #fff3e0, #ffe0b2);
|
|
border: 2rpx dashed #ff9800;
|
|
border-radius: 12rpx;
|
|
padding: 36rpx 24rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
.code-text {
|
|
font-size: 56rpx;
|
|
font-weight: 700;
|
|
color: #e65100;
|
|
letter-spacing: 4rpx;
|
|
font-family: Menlo, Monaco, monospace;
|
|
}
|
|
.copy-btn {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
background: #ff9800;
|
|
color: #fff;
|
|
border-radius: 8rpx;
|
|
padding: 12rpx 20rpx;
|
|
font-size: 24rpx;
|
|
.iconfont { font-size: 30rpx; margin-bottom: 4rpx; }
|
|
}
|
|
&.placeholder {
|
|
background: #f5f5f5;
|
|
border-color: #ccc;
|
|
justify-content: center;
|
|
min-height: 100rpx;
|
|
.placeholder-text {
|
|
color: #999;
|
|
font-size: 28rpx;
|
|
}
|
|
}
|
|
}
|
|
.share-bar {
|
|
margin-top: 16rpx;
|
|
.icon-share { font-size: 28rpx; color: #ff9800; margin-right: 8rpx; }
|
|
.share-tip {
|
|
font-size: 24rpx;
|
|
color: #666;
|
|
}
|
|
.share-link-card {
|
|
margin-top: 12rpx;
|
|
background: #fafafa;
|
|
border-radius: 8rpx;
|
|
padding: 16rpx 20rpx;
|
|
.link-text {
|
|
font-size: 24rpx;
|
|
color: #444;
|
|
word-break: break-all;
|
|
}
|
|
}
|
|
}
|
|
.copy-toast {
|
|
position: fixed;
|
|
top: 50%; left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: rgba(0,0,0,0.7);
|
|
color: #fff;
|
|
padding: 16rpx 32rpx;
|
|
border-radius: 8rpx;
|
|
font-size: 28rpx;
|
|
z-index: 9999;
|
|
}
|
|
}
|
|
</style>
|