私域操盘手 - 流量池数据统计
This commit is contained in:
@@ -88,10 +88,11 @@ interface TrafficPoolResponse {
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
statistics: {
|
||||
total: number
|
||||
todayNew: number
|
||||
}
|
||||
}
|
||||
|
||||
interface Statistics {
|
||||
totalCount: number
|
||||
todayAddCount: number
|
||||
}
|
||||
|
||||
export default function TrafficPoolPage() {
|
||||
@@ -108,9 +109,9 @@ export default function TrafficPoolPage() {
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
const [isFetching, setIsFetching] = useState(false)
|
||||
const [stats, setStats] = useState({
|
||||
total: 0,
|
||||
todayNew: 0,
|
||||
const [stats, setStats] = useState<Statistics>({
|
||||
totalCount: 0,
|
||||
todayAddCount: 0
|
||||
})
|
||||
const [selectedUser, setSelectedUser] = useState<TrafficUser | null>(null)
|
||||
const [showUserDetail, setShowUserDetail] = useState(false)
|
||||
@@ -179,7 +180,7 @@ export default function TrafficPoolPage() {
|
||||
} as any)
|
||||
|
||||
if (response.code === 200) {
|
||||
const { list, pagination, statistics } = response.data
|
||||
const { list, pagination } = response.data
|
||||
|
||||
const transformedUsers = list.map(user => ({
|
||||
id: user.id.toString(),
|
||||
@@ -200,10 +201,6 @@ export default function TrafficPoolPage() {
|
||||
setUsers(prev => isNewSearch ? transformedUsers : [...prev, ...transformedUsers])
|
||||
setCurrentPage(page)
|
||||
setHasMore(list.length > 0 && page < pagination.totalPages)
|
||||
setStats({
|
||||
total: statistics.total,
|
||||
todayNew: statistics.todayNew
|
||||
})
|
||||
} else {
|
||||
toast({
|
||||
title: "获取数据失败",
|
||||
@@ -281,6 +278,33 @@ export default function TrafficPoolPage() {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const fetchStatistics = useCallback(async () => {
|
||||
try {
|
||||
const response = await api.get<ApiResponse<Statistics>>('/v1/traffic/pool/statistics', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||||
}
|
||||
} as any)
|
||||
|
||||
if (response.code === 200) {
|
||||
setStats(response.data)
|
||||
} else {
|
||||
toast({
|
||||
title: "获取统计数据失败",
|
||||
description: response.msg || "请稍后重试",
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取统计数据失败:", error)
|
||||
toast({
|
||||
title: "获取统计数据失败",
|
||||
description: "请检查网络连接或稍后重试",
|
||||
variant: "destructive",
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = useCallback(() => {
|
||||
setUsers([])
|
||||
@@ -315,6 +339,7 @@ export default function TrafficPoolPage() {
|
||||
useEffect(() => {
|
||||
fetchStatusTypes()
|
||||
fetchSourceTypes()
|
||||
fetchStatistics()
|
||||
fetchUsers(1, true)
|
||||
}, [])
|
||||
|
||||
@@ -377,11 +402,11 @@ export default function TrafficPoolPage() {
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Card className="p-4">
|
||||
<div className="text-sm text-gray-500">流量池总数</div>
|
||||
<div className="text-2xl font-bold text-blue-600">{stats.total}</div>
|
||||
<div className="text-2xl font-bold text-blue-600">{stats.totalCount}</div>
|
||||
</Card>
|
||||
<Card className="p-4">
|
||||
<div className="text-sm text-gray-500">今日新增</div>
|
||||
<div className="text-2xl font-bold text-green-600">{stats.todayNew}</div>
|
||||
<div className="text-2xl font-bold text-green-600">{stats.todayAddCount}</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,6 +9,14 @@ use think\Model;
|
||||
*/
|
||||
class TrafficSource extends Model
|
||||
{
|
||||
const STATUS_PENDING = 1; // 待处理
|
||||
const STATUS_WORKING = 2; // 处理中
|
||||
const STATUS_PASSED = 3; // 已通过
|
||||
const STATUS_REFUSED = 4; // 已拒绝
|
||||
const STATUS_EXPIRED = 5; // 已过期
|
||||
const STATUS_CANCELED = 6; // 已取消
|
||||
|
||||
|
||||
// 设置数据表名
|
||||
protected $name = 'traffic_source';
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ Route::group('v1/', function () {
|
||||
Route::get('', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@index');
|
||||
Route::get('types', 'app\cunkebao\controller\traffic\GetPotentialTypeSectionV1Controller@index');
|
||||
Route::get('sources', 'app\cunkebao\controller\traffic\GetTrafficSourceSectionV1Controller@index');
|
||||
Route::get('statistics', 'app\cunkebao\controller\traffic\GetPoolStatisticsV1Controller@index');
|
||||
});
|
||||
|
||||
// 工作台相关
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace app\cunkebao\controller\traffic;
|
||||
|
||||
use app\common\model\TrafficSource as TrafficSourceModel;
|
||||
use app\cunkebao\controller\BaseController;
|
||||
use library\ResponseHelper;
|
||||
|
||||
/**
|
||||
* 流量池控制器
|
||||
*/
|
||||
class GetPoolStatisticsV1Controller extends BaseController
|
||||
{
|
||||
/**
|
||||
* 获取今日转化数量
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getTodayAddedCount(): int
|
||||
{
|
||||
return TrafficSourceModel::where(
|
||||
[
|
||||
'companyId' => $this->getUserInfo('companyId'),
|
||||
'status' => TrafficSourceModel::STATUS_PASSED,
|
||||
]
|
||||
)
|
||||
->whereBetween('updateTime',
|
||||
[
|
||||
strtotime(date('Y-m-d 00:00:00')),
|
||||
strtotime(date('Y-m-d 23:59:59'))
|
||||
]
|
||||
)
|
||||
->count('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流量池总数
|
||||
*
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getTotalCount(): int
|
||||
{
|
||||
return TrafficSourceModel::where(
|
||||
[
|
||||
'companyId' => $this->getUserInfo('companyId')
|
||||
]
|
||||
)
|
||||
->count('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流量池数据统计
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
try {
|
||||
return ResponseHelper::success(
|
||||
[
|
||||
'totalCount' => $this->getTotalCount(),
|
||||
'todayAddCount' => $this->getTodayAddedCount(),
|
||||
]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
return ResponseHelper::error($e->getMessage(), $e->getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace app\cunkebao\controller\traffic;
|
||||
|
||||
use app\common\model\TrafficPool as TrafficPoolModel;
|
||||
use app\common\model\TrafficSource as TrafficSourceModel;
|
||||
use app\common\model\WechatFriendShip as WechatFriendShipModel;
|
||||
use app\cunkebao\controller\BaseController;
|
||||
use library\ResponseHelper;
|
||||
@@ -21,23 +22,23 @@ class GetPotentialTypeSectionV1Controller extends BaseController
|
||||
{
|
||||
return [
|
||||
[
|
||||
'id' => 1,
|
||||
'id' => TrafficSourceModel::STATUS_PENDING,
|
||||
'name' => '待处理'
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'id' => TrafficSourceModel::STATUS_WORKING,
|
||||
'name' => '处理中'
|
||||
],
|
||||
[
|
||||
'id' => 4,
|
||||
'id' => TrafficSourceModel::STATUS_REFUSED,
|
||||
'name' => '已拒绝'
|
||||
],
|
||||
[
|
||||
'id' => 5,
|
||||
'id' => TrafficSourceModel::STATUS_EXPIRED,
|
||||
'name' => '已过期'
|
||||
],
|
||||
[
|
||||
'id' => 6,
|
||||
'id' => TrafficSourceModel::STATUS_CANCELED,
|
||||
'name' => '已取消'
|
||||
]
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user