## GitHub 同步说明 | 项 | 内容 | |:---|:---| | 仓库 | https://github.com/fnvtk/cunkebao_v3 | | 分支 | develop | | 方向 | 本地 → GitHub(单向 push) | | 是否拉取远程 | 否(未 fetch / pull / merge) | | 是否改本地源文件 | 否(仅 git add/commit,未编辑业务/文档正文) | | 远程基准 | origin/develop @b5b40e8b| | 本批工作区变更 | 999 files, +47622 / -4007 lines | ## 一并推送的本地已有 commit(此前未 push) 1.3aa7ecf8deploy: 官网 ckb.quwanzhi.com 宝塔上线 DNS+SSL+验收文档 2.16a70045fix(官网): 桌面导航仅保留一个留资 CTA 并重新上线 3.dbe7b7aafix(官网): Hero 改为主 CTA 按钮并去掉重复 1200+ 数据条 4.ac82726echore(部署): 五端上线验收46项并统一留资与缓存版本 ## 本 commit 目录统计 | 目录 | 文件数 | 说明 | |:---|---:|:---| | 开发文档/ | 639 | 10、项目管理、未完成项跨仓汇总、五端需求/部署/接口 | | Server/ | 129 | 后端 API、迁移、部署相关 | | Touchkebao/ | 80 | PC 工作台、获客、算力 | | 官网/ | 61 | ckb.quwanzhi.com 静态站与 CTA 迭代 | | Cunkebao/ | 49 | 移动端场景/设置/流量池 | | SuperAdmin/ | 26 | 超管后台 | | .cursor/ | 11 | 规则与 Skill | | 其他 | 14 | docker-compose、.obsidian、.codegraph 等 | ## 重点文件(本地为准) - 开发文档/1、需求/修改/未完成项与跨仓验收汇总.md - 开发文档/10、项目管理/账号密码与登录环境一览.md - 开发文档/10、项目管理/(新建项目管理目录与截图) - 官网/ 全站 + 宝塔上线文档 - 五端上线验收 46 项(见 ac82726e) ## 刻意未上传 - node_modules/、.DS_Store、.smart-env/ - .开发文档_nested_git_backup/ - **/__pycache__/ ## 验收 - 提交页(含本说明): https://github.com/fnvtk/cunkebao_v3/commit/HEAD - 分支树: https://github.com/fnvtk/cunkebao_v3/tree/develop Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
3.7 KiB
PHP
91 lines
3.7 KiB
PHP
<?php
|
||
|
||
namespace app\superadmin\controller\traffic;
|
||
|
||
use app\common\service\TrafficPoolSystemIdentifierService;
|
||
use app\superadmin\controller\BaseController;
|
||
use app\superadmin\service\CompanyClassificationService;
|
||
use library\ResponseHelper;
|
||
use think\Db;
|
||
|
||
/**
|
||
* 客户池摘要(REQ-SA-80/81)
|
||
* - 全平台只返回摘要,不返回明细列表
|
||
* - 供前端默认引导「先选项目/Top5」使用
|
||
*/
|
||
class GetPoolSummaryController extends BaseController
|
||
{
|
||
public function index()
|
||
{
|
||
$companyId = (int) $this->request->param('companyId/d', 0);
|
||
$pageSize = min(100, max(1, (int) $this->request->param('limit/d', 50)));
|
||
|
||
if ($companyId > 0) {
|
||
$base = Db::name('traffic_pool_company')->alias('tpc')
|
||
->where('tpc.companyId', $companyId)
|
||
->where('tpc.isDel', 0);
|
||
TrafficPoolSystemIdentifierService::applyExcludeToCompanyQuery($base, 'tpc');
|
||
$total = (int) (clone $base)->count('tpc.id');
|
||
$bound = (int) (clone $base)->where('tpc.ownerWechatId', '<>', '')->whereNotNull('tpc.ownerWechatId')->count('tpc.id');
|
||
$unbound = max(0, $total - $bound);
|
||
return ResponseHelper::success([
|
||
'scope' => 'company',
|
||
'companyId' => $companyId,
|
||
'totalCustomers' => $total,
|
||
'boundCustomers' => $bound,
|
||
'unboundCustomers' => $unbound,
|
||
'pageSize' => $pageSize,
|
||
'totalPages' => $pageSize > 0 ? (int) ceil($total / $pageSize) : 0,
|
||
]);
|
||
}
|
||
|
||
$base = Db::name('traffic_pool_company')->alias('tpc')
|
||
->where('tpc.isDel', 0);
|
||
TrafficPoolSystemIdentifierService::applyExcludeToCompanyQuery($base, 'tpc');
|
||
$totalCustomers = (int) (clone $base)->count('tpc.id');
|
||
$boundCustomers = (int) (clone $base)->where('tpc.ownerWechatId', '<>', '')->whereNotNull('tpc.ownerWechatId')->count('tpc.id');
|
||
$unboundCustomers = max(0, $totalCustomers - $boundCustomers);
|
||
|
||
$rows = (clone $base)
|
||
->field('tpc.companyId, COUNT(tpc.id) as customerCount')
|
||
->group('tpc.companyId')
|
||
->order('customerCount', 'desc')
|
||
->limit(50)
|
||
->select();
|
||
$rows = $rows ? (is_array($rows) ? $rows : $rows->toArray()) : [];
|
||
$companyIds = array_values(array_unique(array_map(function ($r) {
|
||
return (int) $r['companyId'];
|
||
}, $rows)));
|
||
$nameMap = [];
|
||
if (!empty($companyIds)) {
|
||
$nameMap = Db::name('company')->whereIn('companyId', $companyIds)->where('deleteTime', 0)->column('name', 'companyId');
|
||
}
|
||
|
||
$classifier = new CompanyClassificationService();
|
||
$metaMap = $classifier->buildMetaMap($companyIds);
|
||
$normalRows = [];
|
||
foreach ($rows as $r) {
|
||
$cid = (int) $r['companyId'];
|
||
$meta = $metaMap[$cid] ?? [];
|
||
if ($classifier->matchesTag($meta, CompanyClassificationService::TAG_NORMAL)) {
|
||
$normalRows[] = [
|
||
'companyId' => $cid,
|
||
'companyName' => (string) ($nameMap[$cid] ?? ('项目#' . $cid)),
|
||
'customerCount' => (int) $r['customerCount'],
|
||
];
|
||
}
|
||
}
|
||
|
||
return ResponseHelper::success([
|
||
'scope' => 'global',
|
||
'totalCustomers' => $totalCustomers,
|
||
'boundCustomers' => $boundCustomers,
|
||
'unboundCustomers' => $unboundCustomers,
|
||
'topNormalProjects' => array_slice($normalRows, 0, 5),
|
||
'pageSize' => $pageSize,
|
||
'totalPages' => $pageSize > 0 ? (int) ceil($totalCustomers / $pageSize) : 0,
|
||
]);
|
||
}
|
||
}
|
||
|