私域操盘手 - 流量池列表已转化的列表数据对接

This commit is contained in:
柳清爽
2025-05-13 17:53:15 +08:00
parent 90c3ed5dc4
commit f44a620020
2 changed files with 115 additions and 51 deletions

View File

@@ -95,6 +95,22 @@ interface Statistics {
todayAddCount: number todayAddCount: number
} }
interface ConvertedUser {
id: number
nickname: string
avatar: string
wechatId: string
fromd: string
tags: string[]
createTime: string
status: number
}
interface ConvertedResponse {
list: ConvertedUser[]
total: number
}
export default function TrafficPoolPage() { export default function TrafficPoolPage() {
const router = useRouter() const router = useRouter()
const searchParams = useSearchParams() const searchParams = useSearchParams()
@@ -155,12 +171,10 @@ export default function TrafficPoolPage() {
limit: "30" limit: "30"
}) })
// 只有在有搜索关键词时才添加 keyword 参数
if (debouncedSearchQuery) { if (debouncedSearchQuery) {
params.append("keyword", debouncedSearchQuery) params.append("keyword", debouncedSearchQuery)
} }
// 只有在选择了特定来源时才添加 fromd 参数
if (sourceFilter !== "all") { if (sourceFilter !== "all") {
const selectedSource = sourceTypes.find(source => source.id.toString() === sourceFilter) const selectedSource = sourceTypes.find(source => source.id.toString() === sourceFilter)
if (selectedSource) { if (selectedSource) {
@@ -168,39 +182,51 @@ export default function TrafficPoolPage() {
} }
} }
// 只有在选择了特定状态时才添加 status 参数
if (statusFilter !== "all") { if (statusFilter !== "all") {
params.append("status", statusFilter) params.append("status", statusFilter)
} }
const response = await api.get<ApiResponse<TrafficPoolResponse>>(`/v1/traffic/pool?${params.toString()}`, { const endpoint = activeCategory === "customer"
headers: { ? '/v1/traffic/pool/converted'
Authorization: `Bearer ${localStorage.getItem('token')}` : '/v1/traffic/pool'
}
} as any) const response = await api.get<ApiResponse<any>>(
`${endpoint}?${params.toString()}`,
{
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`
}
} as any
)
if (response.code === 200) { if (response.code === 200) {
const { list, pagination } = response.data const { list } = response.data
const transformedUsers = list.map(user => ({ const transformedUsers: TrafficUser[] = list.map((user: any) => ({
id: user.id.toString(), id: user.id.toString(),
avatar: user.avatar, avatar: user.avatar,
nickname: user.name || user.nickname || '未知用户', nickname: user.nickname || user.name || '未知用户',
wechatId: user.wechatId, wechatId: user.wechatId,
phone: user.phone, phone: user.phone || '',
region: user.region, region: user.region || '',
note: user.note, note: user.note || '',
status: user.status, status: activeCategory === "customer" ? 3 : user.status,
addTime: formatDateTime(user.createTime), addTime: formatDateTime(user.createTime),
source: user.fromd || '未知来源', source: user.fromd || '未知来源',
assignedTo: user.assignedTo, assignedTo: user.assignedTo || '',
category: user.category || "potential", category: activeCategory as "potential" | "customer" | "lost",
tags: user.tags || [] tags: Array.isArray(user.tags)
? user.tags.map((tag: string) => ({
id: tag,
name: tag,
color: 'bg-blue-100 text-blue-800'
}))
: []
})) }))
setUsers(prev => isNewSearch ? transformedUsers : [...prev, ...transformedUsers]) setUsers(prev => isNewSearch ? transformedUsers : [...prev, ...transformedUsers])
setCurrentPage(page) setCurrentPage(page)
setHasMore(list.length > 0 && page < pagination.totalPages) setHasMore(list.length === 30)
} else { } else {
toast({ toast({
title: "获取数据失败", title: "获取数据失败",
@@ -222,7 +248,7 @@ export default function TrafficPoolPage() {
setIsFetching(false) setIsFetching(false)
setLoading(false) setLoading(false)
} }
}, [debouncedSearchQuery, sourceFilter, statusFilter, sourceTypes]) }, [debouncedSearchQuery, sourceFilter, statusFilter, sourceTypes, activeCategory])
const fetchStatusTypes = useCallback(async () => { const fetchStatusTypes = useCallback(async () => {
try { try {
@@ -456,25 +482,27 @@ export default function TrafficPoolPage() {
</SelectContent> </SelectContent>
</Select> </Select>
<Select {activeCategory === "potential" && (
value={statusFilter} <Select
onValueChange={(value) => { value={statusFilter}
setStatusFilter(value) onValueChange={(value) => {
setCurrentPage(1) setStatusFilter(value)
}} setCurrentPage(1)
> }}
<SelectTrigger className="w-[120px]"> >
<SelectValue placeholder="状态" /> <SelectTrigger className="w-[120px]">
</SelectTrigger> <SelectValue placeholder="状态" />
<SelectContent> </SelectTrigger>
<SelectItem value="all"></SelectItem> <SelectContent>
{statusTypes.map((status) => ( <SelectItem value="all"></SelectItem>
<SelectItem key={status.id} value={status.id.toString()}> {statusTypes.map((status) => (
{status.name} <SelectItem key={status.id} value={status.id.toString()}>
</SelectItem> {status.name}
))} </SelectItem>
</SelectContent> ))}
</Select> </SelectContent>
</Select>
)}
</div> </div>
{/* 用户列表 */} {/* 用户列表 */}
@@ -506,14 +534,22 @@ export default function TrafficPoolPage() {
<div className="font-medium truncate">{user.nickname}</div> <div className="font-medium truncate">{user.nickname}</div>
<div <div
className={`text-xs px-2 py-1 rounded-full ${ className={`text-xs px-2 py-1 rounded-full ${
user.status === 2 activeCategory === "customer"
? "bg-green-100 text-green-800" ? "bg-green-100 text-green-800"
: user.status === 1 : user.status === 2
? "bg-yellow-100 text-yellow-800" ? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800" : user.status === 1
? "bg-yellow-100 text-yellow-800"
: "bg-red-100 text-red-800"
}`} }`}
> >
{user.status === 2 ? "已添加" : user.status === 1 ? "待处理" : "已失败"} {activeCategory === "customer"
? "已通过"
: user.status === 2
? "已添加"
: user.status === 1
? "待处理"
: "已失败"}
</div> </div>
</div> </div>
<div className="text-sm text-gray-500">: {user.wechatId}</div> <div className="text-sm text-gray-500">: {user.wechatId}</div>
@@ -577,14 +613,22 @@ export default function TrafficPoolPage() {
<div className="text-sm text-gray-500">{selectedUser.wechatId}</div> <div className="text-sm text-gray-500">{selectedUser.wechatId}</div>
<Badge <Badge
className={`mt-1 ${ className={`mt-1 ${
selectedUser.status === 2 activeCategory === "customer"
? "bg-green-100 text-green-800" ? "bg-green-100 text-green-800"
: selectedUser.status === 1 : selectedUser.status === 2
? "bg-yellow-100 text-yellow-800" ? "bg-green-100 text-green-800"
: "bg-red-100 text-red-800" : selectedUser.status === 1
? "bg-yellow-100 text-yellow-800"
: "bg-red-100 text-red-800"
}`} }`}
> >
{selectedUser.status === 2 ? "已添加" : selectedUser.status === 1 ? "待处理" : "已失败"} {activeCategory === "customer"
? "已通过"
: selectedUser.status === 2
? "已添加"
: selectedUser.status === 1
? "待处理"
: "已失败"}
</Badge> </Badge>
</div> </div>
</div> </div>

View File

@@ -13,6 +13,25 @@ use library\ResponseHelper;
*/ */
class GetConvertedListWithInCompanyV1Controller extends BaseController class GetConvertedListWithInCompanyV1Controller extends BaseController
{ {
/**
* 构建返回数据
*
* @param \think\Paginator $result
* @return array
*/
protected function makeResultedSet(\think\Paginator $result): array
{
$resultSets = [];
foreach ($result->items() as $item) {
$item->tags = json_decode($item->tags);
array_push($resultSets, $item->toArray());
}
return $resultSets;
}
/** /**
* 构建查询条件 * 构建查询条件
* *
@@ -47,7 +66,8 @@ class GetConvertedListWithInCompanyV1Controller extends BaseController
$query = TrafficSourceModel::alias('s') $query = TrafficSourceModel::alias('s')
->field( ->field(
[ [
'w.id', 'w.nickname', 'w.avatar', 'w.wechatId', 'w.id', 'w.nickname', 'w.avatar',
'CASE WHEN w.alias IS NULL OR w.alias = "" THEN w.wechatId ELSE w.alias END AS wechatId',
's.fromd', 's.fromd',
'f.tags', 'f.createTime', TrafficSourceModel::STATUS_PASSED . ' status' 'f.tags', 'f.createTime', TrafficSourceModel::STATUS_PASSED . ' status'
] ]
@@ -81,7 +101,7 @@ class GetConvertedListWithInCompanyV1Controller extends BaseController
return ResponseHelper::success( return ResponseHelper::success(
[ [
'list' => $result->items(), 'list' => $this->makeResultedSet($result),
'total' => $result->total(), 'total' => $result->total(),
] ]
); );