feat: 运营-用户功能四大需求完整实现
1. 客资中心:Dashboard 聚合 CKB 线索+提交记录,联表用户信息 2. @置顶:Person 三端(后端+管理端+小程序)置顶功能,首页优先展示 3. 存客宝场景:一键检查并自动启用所有场景获客计划 4. 去重增强:后端聚合 dupCount,管理端展示重复标记和统计 5. 首页文案:"最新更新"→"推荐","开始阅读"→"点击阅读" Made-with: Cursor
This commit is contained in:
@@ -33,7 +33,7 @@ Page({
|
||||
|
||||
// 最新章节(动态计算)
|
||||
latestSection: null,
|
||||
latestLabel: '最新更新',
|
||||
latestLabel: '推荐',
|
||||
|
||||
// 内容概览
|
||||
partsList: [
|
||||
@@ -135,29 +135,63 @@ Page({
|
||||
async loadSuperMembers() {
|
||||
this.setData({ superMembersLoading: true })
|
||||
try {
|
||||
// 并行请求 VIP 会员和普通用户,合并后取前 4 个(VIP 优先)
|
||||
const [vipRes, usersRes] = await Promise.all([
|
||||
const [pinnedRes, vipRes, usersRes] = await Promise.all([
|
||||
app.request({ url: '/api/miniprogram/persons/pinned', silent: true }).catch(() => null),
|
||||
app.request({ url: '/api/miniprogram/vip/members', silent: true }).catch(() => null),
|
||||
app.request({ url: '/api/miniprogram/users?limit=20', silent: true }).catch(() => null)
|
||||
])
|
||||
let members = []
|
||||
if (vipRes && vipRes.success && Array.isArray(vipRes.data) && vipRes.data.length > 0) {
|
||||
members = vipRes.data.slice(0, 4).map(u => ({
|
||||
id: u.id,
|
||||
name: u.nickname || u.vipName || u.vip_name || '会员',
|
||||
avatar: u.avatar || '',
|
||||
isVip: true
|
||||
}))
|
||||
if (members.length > 0) console.log('[Index] 超级个体加载成功:', members.length, '人')
|
||||
const usedIds = new Set()
|
||||
|
||||
// 1. 后台置顶人物优先(最多 4 个)
|
||||
if (pinnedRes && pinnedRes.success && Array.isArray(pinnedRes.persons)) {
|
||||
pinnedRes.persons.slice(0, 4).forEach(p => {
|
||||
const id = p.userId || p.personId
|
||||
members.push({
|
||||
id,
|
||||
personId: p.personId,
|
||||
name: p.nickname || p.name || '置顶',
|
||||
avatar: p.avatar || '',
|
||||
isVip: true,
|
||||
isPinned: true
|
||||
})
|
||||
usedIds.add(id)
|
||||
})
|
||||
}
|
||||
|
||||
// 2. VIP 会员补位
|
||||
if (members.length < 4 && vipRes && vipRes.success && Array.isArray(vipRes.data)) {
|
||||
vipRes.data.forEach(u => {
|
||||
if (members.length >= 4) return
|
||||
if (usedIds.has(u.id)) return
|
||||
members.push({
|
||||
id: u.id,
|
||||
name: u.nickname || u.vipName || u.vip_name || '会员',
|
||||
avatar: u.avatar || '',
|
||||
isVip: true,
|
||||
isPinned: false
|
||||
})
|
||||
usedIds.add(u.id)
|
||||
})
|
||||
}
|
||||
|
||||
// 3. 普通用户兜底
|
||||
if (members.length < 4 && usersRes && usersRes.success && Array.isArray(usersRes.data)) {
|
||||
const existIds = new Set(members.map(m => m.id))
|
||||
const extra = usersRes.data
|
||||
.filter(u => u.avatar && u.nickname && !existIds.has(u.id))
|
||||
.slice(0, 4 - members.length)
|
||||
.map(u => ({ id: u.id, name: u.nickname, avatar: u.avatar, isVip: u.is_vip === 1 }))
|
||||
members = members.concat(extra)
|
||||
usersRes.data
|
||||
.filter(u => u.avatar && u.nickname && !usedIds.has(u.id))
|
||||
.forEach(u => {
|
||||
if (members.length >= 4) return
|
||||
members.push({
|
||||
id: u.id,
|
||||
name: u.nickname,
|
||||
avatar: u.avatar,
|
||||
isVip: u.is_vip === 1,
|
||||
isPinned: false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (members.length > 0) console.log('[Index] 超级个体加载成功:', members.length, '人 (置顶', members.filter(m => m.isPinned).length, '人)')
|
||||
this.setData({ superMembers: members, superMembersLoading: false })
|
||||
} catch (e) {
|
||||
console.log('[Index] 加载超级个体失败:', e)
|
||||
|
||||
@@ -38,18 +38,18 @@
|
||||
<!-- Banner卡片 - 最新章节(异步加载) -->
|
||||
<view class="banner-card" wx:if="{{latestSection}}" bindtap="goToRead" data-id="{{latestSection.id}}" data-mid="{{latestSection.mid}}">
|
||||
<view class="banner-glow"></view>
|
||||
<view class="banner-tag">最新更新</view>
|
||||
<view class="banner-tag">推荐</view>
|
||||
<view class="banner-title">{{latestSection.title}}</view>
|
||||
<view class="banner-action">
|
||||
<text class="banner-action-text">开始阅读</text>
|
||||
<text class="banner-action-text">点击阅读</text>
|
||||
<icon name="chevron-right" size="32" color="#fff" customClass="banner-arrow"></icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="banner-card banner-skeleton" wx:else bindtap="goToChapters">
|
||||
<view class="banner-glow"></view>
|
||||
<view class="banner-tag">最新更新</view>
|
||||
<view class="banner-tag">推荐</view>
|
||||
<view class="banner-title">加载中...</view>
|
||||
<view class="banner-action"><text class="banner-action-text">开始阅读</text><icon name="chevron-right" size="32" color="#fff" customClass="banner-arrow"></icon></view>
|
||||
<view class="banner-action"><text class="banner-action-text">点击阅读</text><icon name="chevron-right" size="32" color="#fff" customClass="banner-arrow"></icon></view>
|
||||
</view>
|
||||
|
||||
<!-- 超级个体(横向滚动,已去掉「查看全部」;审核模式隐藏) -->
|
||||
@@ -70,15 +70,16 @@
|
||||
<scroll-view wx:elif="{{superMembers.length > 0}}" class="super-scroll" scroll-x>
|
||||
<view class="super-scroll-inner">
|
||||
<view
|
||||
class="super-item-h"
|
||||
class="super-item-h {{item.isPinned ? 'super-item-pinned' : ''}}"
|
||||
wx:for="{{superMembers}}"
|
||||
wx:key="id"
|
||||
bindtap="goToMemberDetail"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="super-avatar {{item.isVip ? 'super-avatar-vip' : ''}}">
|
||||
<view class="super-avatar {{item.isVip ? 'super-avatar-vip' : ''}} {{item.isPinned ? 'super-avatar-pinned' : ''}}">
|
||||
<image class="super-avatar-img" wx:if="{{item.avatar}}" src="{{item.avatar}}" mode="aspectFill"/>
|
||||
<text class="super-avatar-text" wx:else>{{item.name[0] || '会'}}</text>
|
||||
<view class="pinned-badge" wx:if="{{item.isPinned}}">★</view>
|
||||
</view>
|
||||
<text class="super-name">{{item.name}}</text>
|
||||
</view>
|
||||
|
||||
@@ -634,10 +634,11 @@
|
||||
gap: 10rpx;
|
||||
}
|
||||
.super-avatar {
|
||||
position: relative;
|
||||
width: 108rpx;
|
||||
height: 108rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
background: rgba(0,206,209,0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -648,10 +649,33 @@
|
||||
border: 3rpx solid #FFD700;
|
||||
box-shadow: 0 0 12rpx rgba(255,215,0,0.3);
|
||||
}
|
||||
.super-avatar-pinned {
|
||||
border: 3rpx solid #38bdac;
|
||||
box-shadow: 0 0 16rpx rgba(56, 189, 172, 0.4);
|
||||
}
|
||||
.super-item-pinned .super-name {
|
||||
color: #38bdac;
|
||||
}
|
||||
.pinned-badge {
|
||||
position: absolute;
|
||||
bottom: -4rpx;
|
||||
right: -4rpx;
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
background: #38bdac;
|
||||
border-radius: 50%;
|
||||
font-size: 18rpx;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
.super-avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.super-avatar-text {
|
||||
font-size: 40rpx;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user