调整流量池数据结构
This commit is contained in:
@@ -3,6 +3,7 @@ namespace app\superadmin\controller;
|
||||
|
||||
use app\superadmin\model\TrafficPool as TrafficPoolModel;
|
||||
use think\Controller;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 客户池控制器
|
||||
@@ -16,102 +17,66 @@ class TrafficPool extends Controller
|
||||
public function getList()
|
||||
{
|
||||
// 获取分页参数
|
||||
$page = $this->request->param('page/d', 1);
|
||||
$limit = $this->request->param('limit/d', 20);
|
||||
$keyword = $this->request->param('keyword/s', '');
|
||||
$page = Request::param('page/d', 1);
|
||||
$limit = Request::param('limit/d', 30);
|
||||
|
||||
// 构建查询条件
|
||||
$where = [];
|
||||
|
||||
// 如果有搜索关键词
|
||||
if (!empty($keyword)) {
|
||||
$where[] = ['tp.nickname|tp.identifier|tp.alias', 'like', "%{$keyword}%"];
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
// 构建查询
|
||||
$query = TrafficPoolModel::alias('tp')
|
||||
// 关联流量来源表
|
||||
->join('traffic_source ts', 'tp.identifier = ts.identifier', 'inner')
|
||||
// 关联公司表
|
||||
->join('company c', 'ts.companyId = c.id', 'left')
|
||||
// 关联微信好友表
|
||||
->join('wechat_friend wf', 'tp.wechatId = wf.wechatId', 'left')
|
||||
// 查询字段
|
||||
->join('traffic_source ts', 'tp.identifier = ts.identifier', 'INNER')
|
||||
->join('company c', 'ts.companyId = c.id', 'LEFT')
|
||||
->join('wechat_account wa', 'tp.wechatId = wa.wechatId', 'LEFT')
|
||||
->join('wechat_tag wt', 'wa.wechatId = wt.wechatId')
|
||||
->field([
|
||||
'distinct ts.identifier',
|
||||
'tp.id',
|
||||
'tp.avatar',
|
||||
'tp.nickname',
|
||||
'tp.wechatId',
|
||||
'tp.mobile',
|
||||
'tp.createTime',
|
||||
'tp.wechatId',
|
||||
'tp.createTime as addTime',
|
||||
'ts.fromd as source',
|
||||
'ts.companyId',
|
||||
'c.name as companyName',
|
||||
'wf.gender',
|
||||
'wf.region',
|
||||
'wf.labels'
|
||||
]);
|
||||
|
||||
// 统计总数
|
||||
$total = $query->where($where)->count();
|
||||
|
||||
// 获取列表数据
|
||||
$list = $query->where($where)
|
||||
->order('tp.createTime', 'desc')
|
||||
->page($page, $limit)
|
||||
->select();
|
||||
|
||||
// 格式化数据
|
||||
$data = [];
|
||||
foreach ($list as $item) {
|
||||
$labels = [];
|
||||
// 处理标签数据
|
||||
if (!empty($item['labels'])) {
|
||||
$labelData = json_decode($item['labels'], true);
|
||||
if (is_array($labelData)) {
|
||||
foreach ($labelData as $label) {
|
||||
if (isset($label['name'])) {
|
||||
$labels[] = $label['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化性别
|
||||
$gender = '未知';
|
||||
switch ($item['gender']) {
|
||||
'c.name as projectName',
|
||||
'wa.avatar',
|
||||
'wa.gender',
|
||||
'wa.nickname',
|
||||
'wa.region',
|
||||
'wt.tags'
|
||||
])
|
||||
->order('tp.createTime DESC');
|
||||
|
||||
// 执行分页查询
|
||||
$list = $query->paginate([
|
||||
'list_rows' => $limit,
|
||||
'page' => $page
|
||||
]);
|
||||
|
||||
// 处理性别显示
|
||||
$list->each(function($item) {
|
||||
// 处理性别显示
|
||||
switch($item['gender']) {
|
||||
case 1:
|
||||
$gender = '男';
|
||||
$item['gender'] = '男';
|
||||
break;
|
||||
case 2:
|
||||
$gender = '女';
|
||||
$item['gender'] = '女';
|
||||
break;
|
||||
default:
|
||||
$item['gender'] = '保密';
|
||||
}
|
||||
|
||||
$data[] = [
|
||||
'id' => $item['id'],
|
||||
'avatar' => $item['avatar'],
|
||||
'nickname' => $item['nickname'],
|
||||
'wechatId' => $item['wechatId'],
|
||||
'gender' => $gender,
|
||||
'region' => $item['region'] ?: '未知',
|
||||
'tags' => empty($labels) ? [] : $labels,
|
||||
'source' => $item['source'] ?: '未知',
|
||||
'companyName' => $item['companyName'] ?: '未知',
|
||||
'createTime' => date('Y-m-d H:i:s', $item['createTime']),
|
||||
'mobile' => $item['mobile']
|
||||
];
|
||||
}
|
||||
|
||||
// 处理标签显示
|
||||
if (is_string($item['tags'])) {
|
||||
$item['tags'] = json_decode($item['tags'], true);
|
||||
}
|
||||
|
||||
return $item;
|
||||
});
|
||||
|
||||
// 返回结果
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '获取成功',
|
||||
'data' => [
|
||||
'list' => $data,
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'limit' => $limit
|
||||
'total' => $list->total(),
|
||||
'list' => $list->items(),
|
||||
'page' => $list->currentPage(),
|
||||
'limit' => $list->listRows()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
13
Server/application/superadmin/model/Scene.php
Normal file
13
Server/application/superadmin/model/Scene.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace app\superadmin\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 场景模型
|
||||
*/
|
||||
class Scene extends Model
|
||||
{
|
||||
// 设置数据表名
|
||||
protected $name = 'scene';
|
||||
}
|
||||
@@ -4,10 +4,45 @@ namespace app\superadmin\model;
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 流量池模型
|
||||
* 客户池模型
|
||||
*/
|
||||
class TrafficPool extends Model
|
||||
{
|
||||
// 设置数据表名
|
||||
protected $name = 'traffic_pool';
|
||||
|
||||
// 设置表前缀
|
||||
protected $prefix = 'ck_';
|
||||
|
||||
// 设置主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 自动写入时间戳
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'createTime';
|
||||
protected $updateTime = 'updateTime';
|
||||
|
||||
// 定义字段类型
|
||||
protected $type = [
|
||||
'id' => 'integer',
|
||||
'wechatId' => 'string',
|
||||
'createTime' => 'datetime',
|
||||
'updateTime' => 'integer'
|
||||
];
|
||||
|
||||
// 定义字段验证规则
|
||||
protected $rule = [
|
||||
'wechatId' => 'require|max:64',
|
||||
'identifier' => 'require|max:64'
|
||||
];
|
||||
|
||||
// 定义字段验证提示信息
|
||||
protected $message = [
|
||||
'wechatId.require' => '微信ID不能为空',
|
||||
'wechatId.max' => '微信ID最多不能超过64个字符',
|
||||
'identifier.require' => '标识符不能为空',
|
||||
'identifier.max' => '标识符最多不能超过64个字符'
|
||||
];
|
||||
}
|
||||
@@ -10,4 +10,41 @@ class TrafficSource extends Model
|
||||
{
|
||||
// 设置数据表名
|
||||
protected $name = 'traffic_source';
|
||||
|
||||
// 设置表前缀
|
||||
protected $prefix = 'ck_';
|
||||
|
||||
// 设置主键
|
||||
protected $pk = 'id';
|
||||
|
||||
// 自动写入时间戳
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'createTime';
|
||||
protected $updateTime = 'updateTime';
|
||||
|
||||
// 定义字段类型
|
||||
protected $type = [
|
||||
'id' => 'integer',
|
||||
'identifier' => 'string',
|
||||
'companyId' => 'integer',
|
||||
'createTime' => 'datetime',
|
||||
'updateTime' => 'integer'
|
||||
];
|
||||
|
||||
// 定义字段验证规则
|
||||
protected $rule = [
|
||||
'identifier' => 'require|max:64',
|
||||
'companyId' => 'number',
|
||||
'fromd' => 'max:255'
|
||||
];
|
||||
|
||||
// 定义字段验证提示信息
|
||||
protected $message = [
|
||||
'identifier.require' => '标识符不能为空',
|
||||
'identifier.max' => '标识符最多不能超过64个字符',
|
||||
'companyId.number' => '公司ID必须为数字',
|
||||
'fromd.max' => '来源最多不能超过255个字符'
|
||||
];
|
||||
}
|
||||
13
Server/application/superadmin/model/WechatAccount.php
Normal file
13
Server/application/superadmin/model/WechatAccount.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace app\superadmin\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 微信账号模型
|
||||
*/
|
||||
class WechatAccount extends Model
|
||||
{
|
||||
// 设置数据表名
|
||||
protected $name = 'wechat_account';
|
||||
}
|
||||
13
Server/application/superadmin/model/WechatTag.php
Normal file
13
Server/application/superadmin/model/WechatTag.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace app\superadmin\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 微信标签模型
|
||||
*/
|
||||
class WechatTag extends Model
|
||||
{
|
||||
// 设置数据表名
|
||||
protected $name = 'wechat_tag';
|
||||
}
|
||||
@@ -123,7 +123,7 @@ export default function CustomersPage() {
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalPages, setTotalPages] = useState(1)
|
||||
const [totalItems, setTotalItems] = useState(0)
|
||||
const [pageSize, setPageSize] = useState(10)
|
||||
const [pageSize, setPageSize] = useState(30)
|
||||
const [jumpToPage, setJumpToPage] = useState("")
|
||||
|
||||
// 获取客户列表数据
|
||||
@@ -133,7 +133,13 @@ export default function CustomersPage() {
|
||||
try {
|
||||
const response = await getTrafficPoolList(currentPage, pageSize, searchTerm);
|
||||
if (response.code === 200 && response.data) {
|
||||
setCustomers(response.data.list);
|
||||
// 处理标签数据,过滤掉无效标签
|
||||
const processedCustomers = response.data.list.map(customer => ({
|
||||
...customer,
|
||||
tags: customer.tags.filter(tag => tag && tag !== "请选择标签"),
|
||||
createTime: customer.addTime // 统一使用createTime字段
|
||||
}));
|
||||
setCustomers(processedCustomers);
|
||||
setTotalItems(response.data.total);
|
||||
setTotalPages(Math.ceil(response.data.total / pageSize));
|
||||
setError(null);
|
||||
@@ -176,23 +182,23 @@ export default function CustomersPage() {
|
||||
};
|
||||
|
||||
// Filter customers based on search and filters (兼容示例数据)
|
||||
const filteredCustomers = customersData.filter((customer) => {
|
||||
const filteredCustomers = customers.filter((customer) => {
|
||||
const matchesSearch =
|
||||
customer.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
customer.wechatId.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
customer.nickname.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(customersData.map((c) => c.region))]
|
||||
const sources = [...new Set(customersData.map((c) => c.source))]
|
||||
const projects = [...new Set(customersData.map((c) => c.projectName))]
|
||||
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))]
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -323,7 +329,15 @@ export default function CustomersPage() {
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar>
|
||||
<AvatarImage src={customer.avatar} alt={customer.nickname} />
|
||||
<AvatarImage
|
||||
src={customer.avatar || "/placeholder.svg?height=40&width=40"}
|
||||
alt={customer.nickname}
|
||||
onError={(e) => {
|
||||
// 图片加载失败时使用默认图片
|
||||
const target = e.target as HTMLImageElement;
|
||||
target.src = "/placeholder.svg?height=40&width=40";
|
||||
}}
|
||||
/>
|
||||
<AvatarFallback>{customer.nickname.slice(0, 2)}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
@@ -335,17 +349,21 @@ export default function CustomersPage() {
|
||||
<TableCell>{customer.wechatId}</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{customer.tags.map((tag, index) => (
|
||||
<Badge key={index} variant="outline">
|
||||
{tag}
|
||||
</Badge>
|
||||
))}
|
||||
{customer.tags && customer.tags.length > 0 ? (
|
||||
customer.tags.map((tag, index) => (
|
||||
<Badge key={index} variant="outline">
|
||||
{tag}
|
||||
</Badge>
|
||||
))
|
||||
) : (
|
||||
<span className="text-sm text-muted-foreground">无标签</span>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>{customer.region}</TableCell>
|
||||
<TableCell>{customer.source}</TableCell>
|
||||
<TableCell>{customer.companyName}</TableCell>
|
||||
<TableCell>{customer.createTime}</TableCell>
|
||||
<TableCell>{customer.projectName}</TableCell>
|
||||
<TableCell>{customer.createTime || "未记录"}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -393,10 +411,10 @@ export default function CustomersPage() {
|
||||
<SelectValue placeholder={pageSize} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
<SelectItem value="30">30</SelectItem>
|
||||
<SelectItem value="50">50</SelectItem>
|
||||
<SelectItem value="100">100</SelectItem>
|
||||
<SelectItem value="150">150</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="text-sm">条</span>
|
||||
|
||||
@@ -12,8 +12,10 @@ export interface Customer {
|
||||
region: string;
|
||||
tags: string[];
|
||||
source: string;
|
||||
projectName: string;
|
||||
addTime: string | null;
|
||||
createTime: string | null; // 修改为允许null值
|
||||
companyName: string;
|
||||
createTime: string;
|
||||
mobile: number;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user