微信小程序:自定义底栏接入 AI 入口(含图标与样式)、AI 聊天相关页面与历史/报告等能力;审核模式与配置联动;资料/企业/首页/授权等页面与 app 入口配合调整。
后端 API:AI 对话/报告/余额告警 等服务与路由;小程序 tabBar 配置与分润相关能力;出站推送 Webhook 与管理端调试;飞书留资、小程序数据分析 等支撑;多份 数据库迁移(AI 聊天、灵魂文章、tabBar、分润等)。 管理端 / 超管:看板、用户/订单/分销/财务、设置与 小程序 tabBar 管理、分润规则、灵魂文章、AI 配置与监控 等大量页面与能力扩展;主题与布局更新。 抖音小程序:与微信侧在 结果页/购买/个人中心 等方向做了同步或优化。 另含 部署/脚本、开发文档 等配套更新。 邀请码与解锁:后端 分销/邀请码 接口与 add_invite_codes 等 SQL;小程序侧 邀请码弹窗组件、个人中心/推广/多类结果页 的填写入口与 解锁门控(inviteCodeGate、unlockGate);并补充 《小程序解锁引导与邀请码方案》 文档。 超管后台:路由与 企业中心(EnterpriseHub) 等交互与结构优化。 小程序体验:在 首页结果、推广、各测评结果页 上继续打磨;与 邀请码门控、审核门控 小步联动。
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
const { request } = require('../../utils/request.js')
|
||||
const { getEnterpriseIdForApiPayload } = require('../../utils/enterpriseContext.js')
|
||||
const inviteCodeGate = require('../../utils/inviteCodeGate.js')
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
}
|
||||
},
|
||||
|
||||
data: {
|
||||
code: '',
|
||||
submitting: false,
|
||||
maxLen: 32
|
||||
},
|
||||
|
||||
observers: {
|
||||
visible(v) {
|
||||
if (v) {
|
||||
this.setData({ code: '', submitting: false })
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
noop() {},
|
||||
|
||||
onInput(e) {
|
||||
const v = (e.detail && e.detail.value) ? String(e.detail.value) : ''
|
||||
this.setData({ code: v })
|
||||
},
|
||||
|
||||
onMaskSkip() {
|
||||
this.onSkip()
|
||||
},
|
||||
|
||||
onSkip() {
|
||||
inviteCodeGate.markInviteSkipped()
|
||||
this.triggerEvent('skip', {})
|
||||
},
|
||||
|
||||
onConfirmTap() {
|
||||
const raw = (this.data.code || '').trim()
|
||||
if (!raw) {
|
||||
wx.showToast({ title: '请输入邀请码', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (this.data.submitting) return
|
||||
this.setData({ submitting: true })
|
||||
const token = wx.getStorageSync('token')
|
||||
if (!token) {
|
||||
wx.showToast({ title: '请先登录', icon: 'none' })
|
||||
this.setData({ submitting: false })
|
||||
return
|
||||
}
|
||||
const payload = { inviteCode: raw }
|
||||
const eid = getEnterpriseIdForApiPayload()
|
||||
if (eid != null && Number(eid) > 0) {
|
||||
payload.eid = Number(eid)
|
||||
}
|
||||
request({
|
||||
url: '/api/distribution/bind',
|
||||
method: 'POST',
|
||||
data: payload,
|
||||
success: (res) => {
|
||||
const body = res.data || {}
|
||||
if (res.statusCode === 200 && body.code === 200) {
|
||||
inviteCodeGate.markInviteBound()
|
||||
wx.showToast({ title: body.message || '已记录邀请关系', icon: 'success' })
|
||||
this.triggerEvent('success', body.data || {})
|
||||
} else {
|
||||
const msg = body.message || '邀请码无效'
|
||||
wx.showToast({ title: msg, icon: 'none' })
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({ title: '网络错误', icon: 'none' })
|
||||
},
|
||||
complete: () => {
|
||||
this.setData({ submitting: false })
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<view class="icd-mask" wx:if="{{visible}}" catchtouchmove="noop" bindtap="onMaskSkip">
|
||||
<view class="icd-panel" catchtap="noop">
|
||||
<text class="icd-title">填写邀请码</text>
|
||||
<text class="icd-desc">选填。用于参与推广活动或企业活动;可稍后在「推广中心」了解规则。</text>
|
||||
<input
|
||||
class="icd-input"
|
||||
type="text"
|
||||
maxlength="{{maxLen}}"
|
||||
placeholder="字母或数字"
|
||||
placeholder-class="icd-ph"
|
||||
value="{{code}}"
|
||||
bindinput="onInput"
|
||||
confirm-type="done"
|
||||
bindconfirm="onConfirmTap"
|
||||
/>
|
||||
<view class="icd-actions">
|
||||
<button class="icd-btn icd-btn--ghost" hover-class="none" bindtap="onSkip">暂不填写</button>
|
||||
<button class="icd-btn icd-btn--primary" hover-class="none" loading="{{submitting}}" bindtap="onConfirmTap">确认</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -0,0 +1,89 @@
|
||||
.icd-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 12000;
|
||||
background: rgba(15, 23, 42, 0.48);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.icd-panel {
|
||||
width: 100%;
|
||||
max-width: 620rpx;
|
||||
background: #fff;
|
||||
border-radius: 28rpx;
|
||||
padding: 40rpx 36rpx 36rpx;
|
||||
box-shadow: 0 24rpx 80rpx rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
.icd-title {
|
||||
display: block;
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.icd-desc {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.55;
|
||||
color: #6b7280;
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.icd-input {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
padding: 0 28rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 30rpx;
|
||||
color: #111827;
|
||||
background: #f9fafb;
|
||||
border-radius: 16rpx;
|
||||
border: 2rpx solid #e5e7eb;
|
||||
}
|
||||
|
||||
.icd-ph {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.icd-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
margin-top: 36rpx;
|
||||
}
|
||||
|
||||
.icd-btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 16rpx;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.icd-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.icd-btn--ghost {
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
.icd-btn--primary {
|
||||
background: linear-gradient(135deg, #ff6b8a 0%, #ff8e53 100%);
|
||||
color: #fff;
|
||||
}
|
||||
Reference in New Issue
Block a user