fix(dashboard): 规范会员身份与合伙股东概念,彻底清理误导性合伙人词汇并优化自购考核雷达

这个提交包含在:
chen
2026-09-17 14:32:46 +08:00
父节点 464f8b2f38
当前提交 213be6af25
共有 4 个文件被更改,包括 102 次插入 和 39 次删除

查看文件

@@ -62,7 +62,7 @@ class Dashboard extends Common
})
];
// 2. 分销商/合伙人基础数据 (保持向下兼容)
// 2. 合伙股东基础数据 (保持向下兼容)
$agentData = [
'total' => Agent::count(),
'today' => Agent::whereTime('createtime', 'today')->count(),
@@ -194,7 +194,7 @@ class Dashboard extends Common
$activeUserIds = $activeService->activeUserIds($activeWindowStart, $now);
$activeUserMap = array_flip($activeUserIds);
// 全量合伙人基础信息
// 全量合伙股东基础信息
$allAgents = Agent::field('user_id, level, is_venue, is_county, madow, last_self_order_time')->select();
// 收益明细按 (user_id + reward_type) 聚合,精确归集各角色产出收益
@@ -408,7 +408,7 @@ class Dashboard extends Common
'pending_voucher_quota' => number_format($pendingVoucher, 2, '.', ''),
];
// 9. COO 视角:转化复购漏斗、合伙人自购续期雷达、供应链库存与实时待办看板
// 9. COO 视角:转化复购漏斗、合伙股东自购续期雷达、供应链库存与实时待办看板
$paidOrderUsers = Order::whereIn('status', [Order::STATUS_PAID, Order::STATUS_COMPLETED])
->group('user_id')
->field('user_id, count(*) as buy_count')
@@ -428,13 +428,14 @@ class Dashboard extends Common
$repeatPurchaseRate = $paidUsersCount > 0 ? round(($repeatBuyCount / $paidUsersCount) * 100, 1) : 0.0;
$arpu = $paidUsersCount > 0 ? round($netGmv / $paidUsersCount, 2) : 0.0;
// 9.2 合伙人 30 天自购续期雷达 (客观四态分类,避免恐慌误判)
// 9.2 合伙股东 30 天自购续期雷达 (仅统计具备合伙股东身份的会员,避免恐慌误判)
$activePartnersCount = 0;
$warningPartnersCount = 0;
$pendingRenewCount = 0;
$newNoOrderCount = 0;
$warningList = [];
$pendingRenewList = [];
$partnerShareholderCount = 0;
$agentUserIds = array_column(collection($allAgents)->toArray(), 'user_id');
$agentUserMap = [];
@@ -446,12 +447,19 @@ class Dashboard extends Common
}
foreach ($allAgents as $ag) {
$identityData = IdentityService::build($ag);
// 核心业务规范:合伙股东仅是会员体系下的专属进阶身份(创客V1~V6、酒道馆、区县代理)
// 普通会员与品酒师属于基础会员,无需自购考核,排除在股东自购掉队雷达之外
if (empty($identityData['is_partner'])) {
continue;
}
$partnerShareholderCount++;
$uid = (int) $ag->user_id;
$u = $agentUserMap[$uid] ?? null;
$nickname = $u ? ($u->nickname ?: '用户#' . $uid) : ('用户#' . $uid);
$mobile = ($u && $u->mobile) ? substr_replace($u->mobile, '****', 3, 4) : '-';
$avatar = $u ? ($u->avatar ?: '') : '';
$identityData = IdentityService::build($ag);
$identityText = $identityData['identity_text'] ?: ('Lv.' . $ag->level);
$lastTime = (int) $ag->getData('last_self_order_time');
@@ -492,12 +500,18 @@ class Dashboard extends Common
];
}
} else {
// 新成员待自购首购 (尚未下单)
// 新晋股东待自购首购 (尚未下单)
$newNoOrderCount++;
}
}
}
// 股东专属自购达标率(分子为在保合格股东,分母为合伙股东总人数)
$partnerActiveRate = $partnerShareholderCount > 0
? round((($activePartnersCount + $warningPartnersCount) / $partnerShareholderCount) * 100, 1)
: 0.0;
$partnerNetwork['active_rate'] = $partnerActiveRate;
// 9.3 供应链库存安全与动销商品
$onSaleGoodsCount = (int) Goods::where('status', 'up')->count();
$totalStock = (int) SkuPriceModel::where('status', 'up')->sum('stock');
@@ -562,10 +576,10 @@ class Dashboard extends Common
} elseif ($payoutRate <= 50) {
$riskSuggestions[] = "综合拨比 {$payoutRate}%,略高于基础基准,建议提升高毛利商品动销比例。";
} else {
$riskSuggestions[] = "综合拨比 {$payoutRate}% 超出常规安全线,请复核极差与日结各奖项拨出参数。";
$riskSuggestions[] = "综合拨比 {$payoutRate}% 超出常规安全线,请复核进阶与日结各奖励拨出参数。";
}
if ($warningPartnersCount > 0) {
$riskSuggestions[] = "有 {$warningPartnersCount} 位合伙人进入 7 天临近到期预警期,建议及时定向提醒自购续期。";
$riskSuggestions[] = "有 {$warningPartnersCount} 位合伙股东进入 7 天临近到期预警期,建议及时定向提醒自购续期。";
}
if ($pendingWithdrawCount > 0) {
$riskSuggestions[] = "当前有 {$pendingWithdrawCount} 笔提现申请等待审核(¥{$financeOverview['pending_withdraw_amount']}),请及时处理。";
@@ -714,11 +728,11 @@ class Dashboard extends Common
$payoutArr = [];
$periodMadow = 0.00000000;
// 四大分成板块结构
// 四大业务板块结构
$structureMap = [
'push3' => [
'key' => 'push3',
'name' => '直推裂变(推三返一)',
'name' => '推荐开拓奖励',
'types' => ['push3'],
'amount' => 0.00,
'count' => 0,
@@ -726,7 +740,7 @@ class Dashboard extends Common
],
'maker' => [
'key' => 'maker',
'name' => '创客团队(极差/平级/超越)',
'name' => '创客进阶协同奖励',
'types' => ['maker_diff', 'maker_peer', 'maker_overtaken'],
'amount' => 0.00,
'count' => 0,
@@ -734,7 +748,7 @@ class Dashboard extends Common
],
'channel' => [
'key' => 'channel',
'name' => '实体渠道(馆县拆分/平级)',
'name' => '实体统筹协同奖励',
'types' => ['team_venue', 'team_county', 'venue_peer', 'county_peer'],
'amount' => 0.00,
'count' => 0,
@@ -742,7 +756,7 @@ class Dashboard extends Common
],
'share' => [
'key' => 'share',
'name' => '全网共享(平台日结均分)',
'name' => '全网加权贡献奖励',
'types' => ['venue_share', 'county_share'],
'amount' => 0.00,
'count' => 0,

查看文件

@@ -90,7 +90,7 @@
.dashboard-index .font-bold { font-weight: 600; }
.dashboard-index .cursor-pointer { cursor: pointer; }
/* 合伙人网络卡片 */
/* 合伙股东与角色身份网络卡片 */
.dashboard-index .network-card {
padding: 14px 16px;
min-height: 98px;
@@ -505,7 +505,7 @@
<span class="currency">¥</span>{{ state.finance.rigid_cash_liability }}
</div>
<div class="finance-sub-metric sa-flex sa-row-between">
<span>① 用户未提现分润 (随时可提现):</span>
<span>① 用户未提现收益 (随时可提现):</span>
<strong class="text-warning">¥{{ state.finance.commission_float }}</strong>
</div>
<div class="finance-sub-metric sa-flex sa-row-between">
@@ -547,13 +547,13 @@
</div>
</el-col>
<!-- 创客合伙人梯队 -->
<!-- 创客骨干梯队 (合伙股东) -->
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
<div class="network-card card">
<div class="sa-flex sa-row-between mb-2">
<div class="sa-flex">
<span class="network-badge bg-cyan mr-2">创</span>
<span class="font-bold text-dark" style="font-size: 14px;">创客合伙骨干 (V1~V6)</span>
<span class="font-bold text-dark" style="font-size: 14px;">创客骨干 (V1~V6 · 合伙股东)</span>
</div>
<span class="text-cyan font-bold cursor-pointer" style="font-size: 18px;" @click="onOpenAgent('')">
{{ state.partner.maker_count }} <span style="font-size: 12px; color: var(--sa-subfont);">人</span>
@@ -608,14 +608,14 @@
<div class="role-table-card card">
<div class="sa-flex sa-row-between mb-3 sa-flex-wrap">
<div>
<span class="font-bold text-dark" style="font-size: 15px;">全角色身份会员资产与分佣统计全景矩阵</span>
<span class="font-bold text-dark" style="font-size: 15px;">全角色身份会员资产与收益统计全景矩阵</span>
<span style="font-size: 12px; color: var(--sa-subfont); margin-left: 12px;">
逐一统计每一个角色身份的会员人数、持豆存量、实时市值、专属业务分润与笔数
逐一统计每一个会员角色身份(普通会员、品酒师、合伙股东各层级)的人数、持豆存量、实时市值、专属业务收益与笔数
</span>
</div>
<div class="sa-flex" style="margin-top: 4px;">
<el-button size="small" type="primary" plain @click="onOpenAgent('')">合伙股东档案 →</el-button>
<el-button size="small" type="success" plain @click="onOpenReward('')">全部分成流水 →</el-button>
<el-button size="small" type="success" plain @click="onOpenReward('')">全部结算流水 →</el-button>
</div>
</div>
@@ -659,10 +659,10 @@
</template>
</el-table-column>
<el-table-column label="专属业务分佣" min-width="140" align="right">
<el-table-column label="专属业务收益" min-width="140" align="right">
<template #header>
<span style="font-size: 13px;">专属业务分佣</span>
<el-tooltip content="按各角色专属分润类型归集(如创客极差/酒道馆/区县),杜绝一人兼多职时交叉重复计算" placement="top">
<span style="font-size: 13px;">专属业务收益</span>
<el-tooltip content="按各角色专属奖励类型归集(如创客进阶/酒道馆/区县),杜绝一人兼多职时交叉重复计算" placement="top">
<i class="el-icon-info text-muted" style="margin-left: 2px; cursor: pointer;"></i>
</el-tooltip>
</template>
@@ -671,7 +671,7 @@
</template>
</el-table-column>
<el-table-column label="分佣笔数" width="100" align="center">
<el-table-column label="结算笔数" width="100" align="center">
<template #default="scope">
<span class="font-bold">{{ scope.row.reward_count }}</span>
<span style="font-size: 11px; color: var(--sa-subfont);"> 笔</span>
@@ -679,9 +679,15 @@
</el-table-column>
<el-table-column label="30天自购考核" min-width="170">
<template #header>
<span style="font-size: 13px;">30天自购考核</span>
<el-tooltip content="仅具备合伙股东身份(创客V1~V6、酒道馆、区县代理)需按月履行自购以维持分润资格;普通会员及品酒师属于基础会员,无需自购考核" placement="top">
<i class="el-icon-info text-muted" style="margin-left: 2px; cursor: pointer;"></i>
</el-tooltip>
</template>
<template #default="scope">
<div v-if="scope.row.is_exempt_active" class="text-muted" style="font-size: 12px;">
<el-tag size="mini" type="info" effect="plain">{{ scope.row.active_text || '无需自购考核' }}</el-tag>
<el-tag size="mini" type="info" effect="plain">{{ scope.row.active_text || '无需自购考核 (基础会员)' }}</el-tag>
</div>
<div v-else>
<div class="sa-flex sa-row-between" style="font-size: 12px; margin-bottom: 3px;">
@@ -704,7 +710,7 @@
</el-col>
</el-row>
<!-- ================= 2.3 COO 运营全貌 · 用户转化漏斗、合伙人掉队雷达与库存安全 ================= -->
<!-- ================= 2.3 COO 运营全貌 · 用户转化漏斗、合伙股东自购雷达与库存安全 ================= -->
<el-row :gutter="16">
<!-- 左侧:电商用户转化漏斗与复购动销 -->
<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
@@ -752,14 +758,17 @@
</div>
</el-col>
<!-- 中间:合伙人 30 天自购考核与续期雷达 -->
<!-- 中间:合伙股东身份 30 天自购考核与续期雷达 -->
<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
<div class="coo-panel-card card">
<div class="sa-flex sa-row-between mb-3">
<div>
<span class="font-bold text-dark" style="font-size: 14px;">合伙人 30天自购考核与续期雷达</span>
<div class="sa-flex">
<span class="font-bold text-dark" style="font-size: 14px;">合伙股东身份 30天自购考核与续期雷达</span>
<el-tooltip content="合伙股东(创客/酒道馆/区县)是会员专属进阶身份,享有团队分润,需保持 30 天自购活跃;普通会员与品酒师属于基础会员,免于考核" placement="top">
<i class="el-icon-info text-muted" style="margin-left: 4px; cursor: pointer;"></i>
</el-tooltip>
</div>
<span class="cursor-pointer text-primary" style="font-size: 12px;" @click="onOpenAgent('')">合伙团队 →</span>
<span class="cursor-pointer text-primary" style="font-size: 12px;" @click="onOpenAgent('')">合伙股东档案 →</span>
</div>
<!-- 4状态指标标签 -->
@@ -787,7 +796,7 @@
</el-col>
<el-col :span="6">
<div class="radar-stat-pill" style="background: #fafafa; border: 1px solid #d9d9d9; text-align: center; padding: 6px 2px;">
<div style="font-size: 11px; color: #595959;">新成员</div>
<div style="font-size: 11px; color: #595959;">新晋股东</div>
<div style="font-size: 16px; font-weight: bold; color: #595959; margin-top: 2px;">{{ state.operation.new_no_order_partners }}</div>
<div style="font-size: 10px; color: #8c8c8c;">待首购激活</div>
</div>
@@ -797,7 +806,7 @@
<!-- 7天临界断档名单列表(若有则提醒续期,若无则展示待续期列表) -->
<div v-if="state.operation.warning_partners > 0">
<div class="warning-alert-row mb-2 sa-flex sa-row-between">
<span>⚠️ <strong>续期提醒:</strong>以下合伙人自购即将到期</span>
<span>⚠️ <strong>续期提醒:</strong>以下合伙股东自购即将到期</span>
<span style="font-weight: bold;">{{ state.operation.warning_partners }} 人临期</span>
</div>
<div style="max-height: 120px; overflow-y: auto;">
@@ -819,10 +828,10 @@
<div v-else>
<div class="sa-flex sa-row-between" style="background: #f6ffed; border: 1px solid #b7eb8f; padding: 8px 12px; border-radius: 6px; font-size: 12px; color: #389e0d; margin-bottom: 8px;">
<span>🛡️ 合伙团队在保人员健康,暂无 7 天内临期合伙人</span>
<span>🛡️ 合伙股东在保状态健康,暂无 7 天内临期人员</span>
<span>全部在保</span>
</div>
<div style="font-size: 11px; color: var(--sa-subfont); margin-bottom: 4px;">超期待续期合伙人 (自购 1 单即可恢复分润资格):</div>
<div style="font-size: 11px; color: var(--sa-subfont); margin-bottom: 4px;">超期待续期合伙股东 (自购 1 单即可恢复分润资格):</div>
<div style="max-height: 100px; overflow-y: auto;">
<div class="sa-flex sa-row-between mb-1 pb-1" v-for="pUser in state.operation.pending_renew_list.slice(0, 3)" :key="pUser.user_id" style="border-bottom: 1px dashed #f0f2f5; font-size: 12px;">
<div class="sa-flex">
@@ -833,7 +842,7 @@
<el-tag size="mini" type="info" effect="plain">{{ pUser.overdue_text }}</el-tag>
</div>
<div v-if="!state.operation.pending_renew_list || state.operation.pending_renew_list.length === 0" class="text-muted" style="font-size: 11px; text-align: center; padding: 8px 0;">
暂无超期待续期合伙人
暂无超期待续期合伙股东
</div>
</div>
</div>
@@ -863,7 +872,7 @@
</div>
</el-col>
<el-col :span="12" class="mb-2">
<div style="font-size: 11px; color: var(--sa-subfont);">合伙人自购达标率</div>
<div style="font-size: 11px; color: var(--sa-subfont);">合伙股东自购达标率</div>
<div class="sa-flex sa-row-between mt-1">
<strong class="text-dark" style="font-size: 14px;">{{ state.partner?.active_rate || 0 }}%</strong>
<el-tag size="mini" :type="state.operation?.risk_indicators?.partner_active_rate?.status || 'success'">
@@ -981,7 +990,7 @@
</div>
<div class="sa-flex sa-row-between mt-3 pt-2" style="border-top: 1px dashed var(--sa-space); font-size: 12px; color: var(--sa-subfont);">
<span>区间马豆分红:<strong class="text-purple">{{ chart.data.periodMadow }} 豆</strong></span>
<span>区间马豆贡献:<strong class="text-purple">{{ chart.data.periodMadow }} 豆</strong></span>
<el-button type="primary" link size="small" @click="onOpenDaily">日结池详情</el-button>
</div>
</div>
@@ -990,7 +999,7 @@
{/if}
{if $auth->check('shopro/dashboard/ranking')}
<!-- ================= 4. 合伙人收益排行 & 电商运营与风控监控 ================= -->
<!-- ================= 4. 合伙股东收益排行 & 电商运营与风控监控 ================= -->
<el-row :gutter="16">
<!-- 左侧:合伙股东收益排行 TOP 5 -->
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">

查看文件

@@ -811,7 +811,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function (
} else if (item.filter_level) {
onOpenTab(`shopro/commission/agent/index?level=${item.filter_level}`, `${item.role_name}成员`);
} else {
onOpenTab('shopro/commission/agent/index', '合伙人档案');
onOpenTab('shopro/commission/agent/index', '合伙股东档案');
}
}

查看文件

@@ -67,6 +67,7 @@ class DashboardWealthTest
$this->testRankingPartnerAndDailyData();
$this->testWealthFinancialFormulaIntegrity();
$this->testCfoAndCooOverview();
$this->testPartnerShareholderRadarPurity();
echo "\n--------------------------------------------------------\n";
echo "测试执行结果: 通过 {$this->passed} 项, 失败 {$this->failed} 项\n";
@@ -289,6 +290,45 @@ class DashboardWealthTest
);
}
}
/**
* 测试 8:自购雷达纯净性检验(仅合伙股东身份纳入考核,杜绝品酒师与普通会员混入)
*/
public function testPartnerShareholderRadarPurity()
{
$controller = new TestableDashboard();
$controller->total();
$data = $controller->lastOutput['data'] ?? [];
$operation = $data['operation_overview'] ?? [];
$warningList = $operation['warning_list'] ?? [];
$pendingList = $operation['pending_renew_list'] ?? [];
// 验证预警名单中所有人均为合伙股东(创客V1~V6/酒道馆/区县)
$hasNonPartnerInWarning = false;
foreach ($warningList as $wUser) {
$levelText = $wUser['level_text'] ?? '';
if (strpos($levelText, '品酒师') !== false && strpos($levelText, '合伙股东') === false) {
$hasNonPartnerInWarning = true;
}
}
$this->assert(!$hasNonPartnerInWarning, "自购临期预警名单严禁混入普通会员或品酒师,100%为合伙股东身份");
// 验证待续期名单中所有人均为合伙股东
$hasNonPartnerInPending = false;
foreach ($pendingList as $pUser) {
$levelText = $pUser['level_text'] ?? '';
if (strpos($levelText, '品酒师') !== false && strpos($levelText, '合伙股东') === false) {
$hasNonPartnerInPending = true;
}
}
$this->assert(!$hasNonPartnerInPending, "自购买超期待续期名单严禁混入普通会员或品酒师,100%为合伙股东身份");
// 验证 partner_network 中 active_rate 正确性
$partnerNetwork = $data['partner_network'] ?? [];
$activeRate = $partnerNetwork['active_rate'] ?? null;
$this->assert($activeRate !== null && $activeRate >= 0 && $activeRate <= 100, "合伙股东自购达标率 partner_network.active_rate({$activeRate}%) 合法且在区间内");
}
}
if (php_sapi_name() === 'cli' && basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME'])) {