From 213d6dd93efc26f061d5a0c4039140f7cf0e36d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=B3=E6=B8=85=E7=88=BD?= Date: Sun, 13 Apr 2025 13:48:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B6=85=E7=AE=A1=E5=90=8E=E5=8F=B0=20-=20?= =?UTF-8?q?=E6=B5=81=E9=87=8F=E6=B1=A0=E5=AE=A2=E6=88=B7=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/superadmin/config/route.php | 3 +- .../superadmin/controller/TrafficPool.php | 124 +++++++++ SuperAdmin/app/dashboard/customers/page.tsx | 260 ++++++++---------- SuperAdmin/lib/traffic-pool-api.ts | 4 +- 4 files changed, 246 insertions(+), 145 deletions(-) diff --git a/Server/application/superadmin/config/route.php b/Server/application/superadmin/config/route.php index 4127e142..71436418 100644 --- a/Server/application/superadmin/config/route.php +++ b/Server/application/superadmin/config/route.php @@ -27,6 +27,7 @@ Route::group('', function () { // 客户池管理路由 Route::group('trafficPool', function () { - Route::get('list', 'app\\superadmin\\controller\\TrafficPool@getList'); + Route::get('list', 'app\\superadmin\\controller\\TrafficPool@getList'); // 获取客户池列表 + Route::get('detail', 'app\\superadmin\\controller\\TrafficPool@getDetail'); // 获取客户详情 }); })->middleware(['app\\superadmin\\middleware\\AdminAuth']); \ No newline at end of file diff --git a/Server/application/superadmin/controller/TrafficPool.php b/Server/application/superadmin/controller/TrafficPool.php index 6f53170a..27ccd022 100644 --- a/Server/application/superadmin/controller/TrafficPool.php +++ b/Server/application/superadmin/controller/TrafficPool.php @@ -2,8 +2,14 @@ namespace app\superadmin\controller; use app\superadmin\model\TrafficPool as TrafficPoolModel; +use app\superadmin\model\TrafficSource; +use app\superadmin\model\Company; +use app\superadmin\model\WechatAccount; +use app\superadmin\model\WechatTag; use think\Controller; use think\facade\Request; +use think\facade\Session; +use think\facade\Validate; /** * 客户池控制器 @@ -80,4 +86,122 @@ class TrafficPool extends Controller ] ]); } + + /** + * 获取客户详情 + * @return \think\response\Json + */ + public function getDetail() + { + // 获取参数 + $id = Request::param('id/d'); + if (!$id) { + return json(['code' => 400, 'msg' => '参数错误']); + } + + try { + // 查询流量来源信息 + $sourceInfo = TrafficSource::alias('ts') + ->join('company c', 'ts.companyId = c.id', 'LEFT') + ->field([ + 'ts.fromd as source', + 'ts.createTime as addTime', + 'c.name as projectName', + 'ts.identifier' + ]) + ->where('ts.id', $id) + ->find(); + + if (!$sourceInfo) { + return json(['code' => 404, 'msg' => '记录不存在']); + } + + // 查询客户池信息 + $poolInfo = TrafficPoolModel::where('identifier', $sourceInfo['identifier']) + ->field('wechatId') + ->find(); + + $result = [ + 'source' => $sourceInfo['source'], + 'addTime' => $sourceInfo['addTime'], + 'projectName' => $sourceInfo['projectName'] + ]; + + // 如果存在微信ID,查询微信账号信息 + if ($poolInfo && $poolInfo['wechatId']) { + // 查询微信账号信息 + $wechatInfo = WechatAccount::where('wechatId', $poolInfo['wechatId']) + ->field('avatar,nickname,region,gender') + ->find(); + + if ($wechatInfo) { + $result = array_merge($result, [ + 'avatar' => $wechatInfo['avatar'], + 'nickname' => $wechatInfo['nickname'], + 'region' => $wechatInfo['region'], + 'gender' => $this->formatGender($wechatInfo['gender']) + ]); + + // 查询标签信息 + $tagInfo = WechatTag::where('wechatId', $poolInfo['wechatId']) + ->field('tags') + ->find(); + + if ($tagInfo) { + $result['tags'] = is_string($tagInfo['tags']) ? + json_decode($tagInfo['tags'], true) : + $tagInfo['tags']; + } else { + $result['tags'] = []; + } + } + } else { + $result = array_merge($result, [ + 'avatar' => '', + 'nickname' => '未知', + 'region' => '未知', + 'gender' => $this->formatGender(0), + 'tags' => [] + ]); + } + + return json([ + 'code' => 200, + 'msg' => '获取成功', + 'data' => $result + ]); + + } catch (\Exception $e) { + return json([ + 'code' => 500, + 'msg' => '系统错误:' . $e->getMessage() + ]); + } + } + + /** + * 格式化性别显示 + * @param int $gender + * @return string + */ + protected function formatGender($gender) + { + switch($gender) { + case 1: + return '男'; + case 2: + return '女'; + default: + return '保密'; + } + } + + /** + * 检查登录状态 + * @return bool + */ + protected function checkLogin() + { + return Session::has('admin_id'); + } } \ No newline at end of file diff --git a/SuperAdmin/app/dashboard/customers/page.tsx b/SuperAdmin/app/dashboard/customers/page.tsx index 478bd3e1..e966abc7 100644 --- a/SuperAdmin/app/dashboard/customers/page.tsx +++ b/SuperAdmin/app/dashboard/customers/page.tsx @@ -13,7 +13,7 @@ import { DropdownMenuSeparator, } from "@/components/ui/dropdown-menu" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" -import { Search, MoreHorizontal, Eye, UserPlus, Filter, ChevronLeft, ChevronRight, RefreshCw } from "lucide-react" +import { Search, MoreHorizontal, Eye, UserPlus, Filter, ChevronLeft, ChevronRight } from "lucide-react" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { getTrafficPoolList } from "@/lib/traffic-pool-api" @@ -123,18 +123,9 @@ export default function CustomersPage() { const [currentPage, setCurrentPage] = useState(1) const [totalPages, setTotalPages] = useState(1) const [totalItems, setTotalItems] = useState(0) - const [pageSize, setPageSize] = useState(30) + const [pageSize, setPageSize] = useState(10) const [jumpToPage, setJumpToPage] = useState("") - // 添加重置函数 - const handleReset = () => { - setSearchTerm("") - setSelectedRegion("") - setSelectedGender("") - setSelectedSource("") - setSelectedProject("") - } - // 获取客户列表数据 useEffect(() => { const fetchCustomers = async () => { @@ -142,13 +133,7 @@ export default function CustomersPage() { try { const response = await getTrafficPoolList(currentPage, pageSize, searchTerm); if (response.code === 200 && response.data) { - // 处理标签数据,过滤掉无效标签 - const processedCustomers = response.data.list.map(customer => ({ - ...customer, - tags: customer.tags.filter(tag => tag && tag !== "请选择标签"), - createTime: customer.addTime // 统一使用createTime字段 - })); - setCustomers(processedCustomers); + setCustomers(response.data.list); setTotalItems(response.data.total); setTotalPages(Math.ceil(response.data.total / pageSize)); setError(null); @@ -191,124 +176,121 @@ export default function CustomersPage() { }; // Filter customers based on search and filters (兼容示例数据) - const filteredCustomers = customers.filter((customer) => { + const filteredCustomers = customersData.filter((customer) => { const matchesSearch = - customer.nickname.toLowerCase().includes(searchTerm.toLowerCase()) || - customer.wechatId.toLowerCase().includes(searchTerm.toLowerCase()); + customer.name.toLowerCase().includes(searchTerm.toLowerCase()) || + customer.wechatId.toLowerCase().includes(searchTerm.toLowerCase()) - const matchesRegion = selectedRegion ? customer.region === selectedRegion : true; - const matchesGender = selectedGender ? customer.gender === selectedGender : true; - const matchesSource = selectedSource ? customer.source === selectedSource : true; - const matchesProject = selectedProject ? customer.projectName === selectedProject : true; + const matchesRegion = selectedRegion ? customer.region === selectedRegion : true + const matchesGender = selectedGender ? customer.gender === selectedGender : true + const matchesSource = selectedSource ? customer.source === selectedSource : true + const matchesProject = selectedProject ? customer.projectName === selectedProject : true - return matchesSearch && matchesRegion && matchesGender && matchesSource && matchesProject; - }); + return matchesSearch && matchesRegion && matchesGender && matchesSource && matchesProject + }) // Get unique values for filters - const regions = [...new Set(customers.map((c) => c.region))] - const sources = [...new Set(customers.map((c) => c.source))] - const projects = [...new Set(customers.map((c) => c.projectName))] + const regions = [...new Set(customersData.map((c) => c.region))] + const sources = [...new Set(customersData.map((c) => c.source))] + const projects = [...new Set(customersData.map((c) => c.projectName))] return ( -
-
+
+

客户池

-
-
- - setSearchTerm(e.target.value)} - /> +
+
+
+ + setSearchTerm(e.target.value)} + /> +
+ + + + + +
+

地区

+ +
+ +
+

性别

+ +
+ +
+

来源

+ +
+ +
+

所属项目

+ +
+
+
- - - - - -
-

地区

- -
- -
-

性别

- -
- -
-

来源

- -
- -
-

所属项目

- -
-
-
- -
-
-
+
@@ -361,21 +343,17 @@ export default function CustomersPage() { {customer.wechatId}
- {customer.tags && customer.tags.length > 0 ? ( - customer.tags.map((tag, index) => ( - - {tag} - - )) - ) : ( - 无标签 - )} + {customer.tags.map((tag, index) => ( + + {tag} + + ))}
{customer.region} {customer.source} - {customer.projectName} - {customer.createTime || "未记录"} + {customer.companyName} + {customer.createTime} @@ -408,12 +386,10 @@ export default function CustomersPage() {
-
- - {/* 固定在底部的分页控件 */} - {!isLoading && !error && customers.length > 0 && ( -
-
+ + {/* 分页控件 */} + {!isLoading && !error && customers.length > 0 && ( +
共 {totalItems} 条记录,当前第 {currentPage}/{totalPages} 页 @@ -425,10 +401,10 @@ export default function CustomersPage() { + 10 30 50 100 - 150 @@ -446,12 +422,14 @@ export default function CustomersPage() { {/* 数字分页按钮 */} {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => { + // 显示当前页码前后2页,以及第一页和最后一页 const shouldShow = page === 1 || page === totalPages || (page >= currentPage - 2 && page <= currentPage + 2); if (!shouldShow) { + // 显示省略号 if (page === currentPage - 3 || page === currentPage + 3) { return ( @@ -508,8 +486,8 @@ export default function CustomersPage() {
-
- )} + )} +
) } diff --git a/SuperAdmin/lib/traffic-pool-api.ts b/SuperAdmin/lib/traffic-pool-api.ts index 4f9f2dbc..39f77dfa 100644 --- a/SuperAdmin/lib/traffic-pool-api.ts +++ b/SuperAdmin/lib/traffic-pool-api.ts @@ -12,10 +12,8 @@ export interface Customer { region: string; tags: string[]; source: string; - projectName: string; - addTime: string | null; - createTime: string | null; // 修改为允许null值 companyName: string; + createTime: string; mobile: number; }