|
@@ -510,7 +510,7 @@ class Customer extends Start_Controller {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
- public function _dgso()
|
|
|
|
|
|
|
+ public function _dgso——tmp()
|
|
|
{
|
|
{
|
|
|
$user = $this->user->get_api($_SESSION['api']);
|
|
$user = $this->user->get_api($_SESSION['api']);
|
|
|
if($user)
|
|
if($user)
|
|
@@ -2835,4 +2835,321 @@ class Customer extends Start_Controller {
|
|
|
}
|
|
}
|
|
|
$this->_Template('customer_newold',$this->data);
|
|
$this->_Template('customer_newold',$this->data);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * _dgsov1 - 优化版的_dgso方法
|
|
|
|
|
+ * 改进点:
|
|
|
|
|
+ * 1. 修复SQL注入漏洞,使用escape转义
|
|
|
|
|
+ * 2. 修复$d[0]越界问题
|
|
|
|
|
+ * 3. _dgcz改用BFS非递归算法,避免递归爆炸
|
|
|
|
|
+ * 4. 批量预加载关联数据,解决N+1查询
|
|
|
|
|
+ * 5. 修复特殊搜索路径的分页逻辑
|
|
|
|
|
+ * 6. 使用map映射替代硬编码if-else
|
|
|
|
|
+ * 7. 添加输入参数校验
|
|
|
|
|
+ * 8. 未使用的筛选参数(shop/name/level/时间范围)添加为实际筛选条件
|
|
|
|
|
+ */
|
|
|
|
|
+ public function _dgso()
|
|
|
|
|
+ {
|
|
|
|
|
+ $user = $this->user->get_api($_SESSION['api']);
|
|
|
|
|
+ if (!$user)
|
|
|
|
|
+ {
|
|
|
|
|
+ $vip = 0;
|
|
|
|
|
+ die("请先登录!!!");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $fgshop = "";
|
|
|
|
|
+ $sid = "";
|
|
|
|
|
+ $users = explode('|', trim($user['shop'], '|'));
|
|
|
|
|
+ foreach ($users as $value)
|
|
|
|
|
+ {
|
|
|
|
|
+ $fgshop .= " shop = " . intval($value) . " or";
|
|
|
|
|
+ $sid .= " id = " . intval($value) . " or";
|
|
|
|
|
+ }
|
|
|
|
|
+ $vip = ($user['vip'] == 1) ? 1 : 0;
|
|
|
|
|
+
|
|
|
|
|
+ $post = $this->input->post(NULL, TRUE);
|
|
|
|
|
+ if (!isset($post['page']))
|
|
|
|
|
+ {
|
|
|
|
|
+ $wlshop = $this->shop->find_all('1=1 and ' . rtrim($sid, 'or'));
|
|
|
|
|
+ $this->data['wlshop'] = $wlshop;
|
|
|
|
|
+ $this->data['vip'] = $vip;
|
|
|
|
|
+ $this->_Template('customer_dgso', $this->data);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 输入校验:page和perpage必须是正整数
|
|
|
|
|
+ $page = max(1, intval($this->input->post('page', true)));
|
|
|
|
|
+ $perpage = max(1, min(200, intval($this->input->post('perpage', true))));
|
|
|
|
|
+
|
|
|
|
|
+ // 获取搜索参数
|
|
|
|
|
+ $shop = intval($this->input->post('shop', true));
|
|
|
|
|
+ $numphone = $this->input->post('numphone', true);
|
|
|
|
|
+ $name = trim($this->input->post('name', true));
|
|
|
|
|
+ $email = trim($this->input->post('email', true));
|
|
|
|
|
+ $address = trim($this->input->post('address', true));
|
|
|
|
|
+ $level = intval($this->input->post('level', true));
|
|
|
|
|
+ $num = intval($this->input->post('num', true));
|
|
|
|
|
+ $timetk = $this->input->post('timetk', true);
|
|
|
|
|
+ $timetj = $this->input->post('timetj', true);
|
|
|
|
|
+ $timetk = strtotime($timetk);
|
|
|
|
|
+ $timetj = strtotime($timetj);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建WHERE条件,使用escape防SQL注入
|
|
|
|
|
+ $where = "1=1 and (" . rtrim($fgshop, 'or') . ")";
|
|
|
|
|
+
|
|
|
|
|
+ if ($numphone)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and numphone = " . $this->db->escape($numphone);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($email)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and email like '%" . $this->db->escape_like_str($email) . "%'";
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($address)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and address like '%" . $this->db->escape_like_str($address) . "%'";
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($shop)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and shop = " . intval($shop);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($name)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and name like '%" . $this->db->escape_like_str($name) . "%'";
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($level)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and level = " . intval($level);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($num)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and num = " . intval($num);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($timetk && $timetj)
|
|
|
|
|
+ {
|
|
|
|
|
+ $where .= " and time >= " . intval($timetk) . " and time <= " . intval($timetj);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $fields = 'id,shop,source,name,email,country,level,money,num,time,type,numphone,address';
|
|
|
|
|
+
|
|
|
|
|
+ if ($numphone || $email || $address)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 特殊搜索路径:通过地址/邮箱/电话查找关联客户
|
|
|
|
|
+ $d = $this->customer->find_all($where);
|
|
|
|
|
+
|
|
|
|
|
+ // 修复:判断$d是否为空,避免越界
|
|
|
|
|
+ if (empty($d))
|
|
|
|
|
+ {
|
|
|
|
|
+ echo json_encode(array('total' => 0, 'over' => 0, 'pagenum' => 0, 'rows' => array()));
|
|
|
|
|
+ exit;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 使用BFS非递归算法查找所有关联客户
|
|
|
|
|
+ $cx = array();
|
|
|
|
|
+ $info_list = $this->_dgczv1($cx, $d);
|
|
|
|
|
+ $info_list = array_values($info_list);
|
|
|
|
|
+ $total = count($info_list);
|
|
|
|
|
+ $pagenum = ceil($total / $perpage);
|
|
|
|
|
+
|
|
|
|
|
+ // 修复:根据当前页码做切片分页
|
|
|
|
|
+ $start = ($page - 1) * $perpage;
|
|
|
|
|
+ $over = $total - ($start + $perpage);
|
|
|
|
|
+ $info_list = array_slice($info_list, $start, $perpage);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // 正常搜索路径
|
|
|
|
|
+ $order_str = "id desc";
|
|
|
|
|
+ $start = ($page - 1) * $perpage;
|
|
|
|
|
+
|
|
|
|
|
+ $info_list = $this->customer->find_all($where, 'id,shop,source,name,email,country,level,money,num,time,type', $order_str, $start, $perpage);
|
|
|
|
|
+ $total = $this->customer->find_count($where);
|
|
|
|
|
+ $pagenum = ceil($total / $perpage);
|
|
|
|
|
+ $over = $total - ($start + $perpage);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 批量预加载关联数据,避免N+1查询
|
|
|
|
|
+ $shopIds = array();
|
|
|
|
|
+ $sourceIds = array();
|
|
|
|
|
+ $countryIds = array();
|
|
|
|
|
+ foreach ($info_list as $value)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!empty($value['shop'])) $shopIds[$value['shop']] = true;
|
|
|
|
|
+ if (!empty($value['source'])) $sourceIds[$value['source']] = true;
|
|
|
|
|
+ if (!empty($value['country'])) $countryIds[$value['country']] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $shopMap = array();
|
|
|
|
|
+ if (!empty($shopIds))
|
|
|
|
|
+ {
|
|
|
|
|
+ $idList = implode(',', array_map('intval', array_keys($shopIds)));
|
|
|
|
|
+ $shopData = $this->shop->find_all("id in ($idList)", 'id,shopname');
|
|
|
|
|
+ foreach ($shopData as $row)
|
|
|
|
|
+ {
|
|
|
|
|
+ $shopMap[$row['id']] = $row['shopname'];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $sourceMap = array();
|
|
|
|
|
+ if (!empty($sourceIds))
|
|
|
|
|
+ {
|
|
|
|
|
+ $idList = implode(',', array_map('intval', array_keys($sourceIds)));
|
|
|
|
|
+ $sourceData = $this->typeclass->find_all("id in ($idList)", 'id,title');
|
|
|
|
|
+ foreach ($sourceData as $row)
|
|
|
|
|
+ {
|
|
|
|
|
+ $sourceMap[$row['id']] = $row['title'];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $countryMap = array();
|
|
|
|
|
+ if (!empty($countryIds))
|
|
|
|
|
+ {
|
|
|
|
|
+ $idList = implode(',', array_map('intval', array_keys($countryIds)));
|
|
|
|
|
+ $countryData = $this->country->find_all("id in ($idList)", 'id,name');
|
|
|
|
|
+ foreach ($countryData as $row)
|
|
|
|
|
+ {
|
|
|
|
|
+ $countryMap[$row['id']] = $row['name'];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Level映射表
|
|
|
|
|
+ $levelMap = array(
|
|
|
|
|
+ 1 => '网红',
|
|
|
|
|
+ 2 => '批发',
|
|
|
|
|
+ 3 => '店铺转线下',
|
|
|
|
|
+ 4 => '线下其他',
|
|
|
|
|
+ 5 => '店内客户',
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 数据后处理
|
|
|
|
|
+ foreach ($info_list as $key => $value)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 使用预加载的map赋值,避免逐条查询
|
|
|
|
|
+ $info_list[$key]['shop'] = isset($shopMap[$value['shop']]) ? $shopMap[$value['shop']] : '';
|
|
|
|
|
+ $info_list[$key]['source'] = isset($sourceMap[$value['source']]) ? $sourceMap[$value['source']] : '';
|
|
|
|
|
+
|
|
|
|
|
+ if ($value['country'] != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ $info_list[$key]['country'] = isset($countryMap[$value['country']]) ? $countryMap[$value['country']] : '未知';
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ $info_list[$key]['country'] = '未知';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 使用map映射替代if-else链
|
|
|
|
|
+ $info_list[$key]['level'] = isset($levelMap[$value['level']]) ? $levelMap[$value['level']] : '未知';
|
|
|
|
|
+
|
|
|
|
|
+ if ($value['time'] != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ $info_list[$key]['time'] = date('Y-m-d', $value['time']);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ $info_list[$key]['time'] = '无';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ($value['type'] != 2)
|
|
|
|
|
+ {
|
|
|
|
|
+ $info_list[$key]['type'] = "<a href='javascript:void(0);' class='window' data-h='/customer/mdedit/" . $value['id'] . "' data-t='客户下单'><b>下单</b></a> <a class='customer' data-type='2' data-t='yr' data-id='" . $value['id'] . "' href='javascript:void(0);'>移入黑名单</a>";
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ $info_list[$key]['type'] = '黑名单客户';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ unset($info_list[$key]['numphone']);
|
|
|
|
|
+ unset($info_list[$key]['address']);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $rows = array('total' => $total, 'over' => $over, 'pagenum' => $pagenum, 'rows' => ($info_list));
|
|
|
|
|
+ echo json_encode($rows);
|
|
|
|
|
+ exit;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * _dgczv1 - 优化版的_dgcz方法
|
|
|
|
|
+ * 使用BFS广度优先搜索替代递归,避免递归爆炸和栈溢出
|
|
|
|
|
+ * 每一层合并所有搜索条件为一次查询,大幅减少数据库请求
|
|
|
|
|
+ */
|
|
|
|
|
+ public function _dgczv1($child, $data)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 初始化已处理集合
|
|
|
|
|
+ foreach ($data as $value)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isset($child[$value['id']]))
|
|
|
|
|
+ {
|
|
|
|
|
+ $child[$value['id']] = $value;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $fields = 'id,shop,source,name,email,country,level,money,num,time,type,numphone,address';
|
|
|
|
|
+
|
|
|
|
|
+ // BFS广度优先搜索
|
|
|
|
|
+ $queue = $data;
|
|
|
|
|
+ $maxIterations = 50; // 安全上限,防止无限循环
|
|
|
|
|
+
|
|
|
|
|
+ while (!empty($queue) && $maxIterations > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ $maxIterations--;
|
|
|
|
|
+
|
|
|
|
|
+ // 收集当前层所有不重复的搜索词
|
|
|
|
|
+ $addressSet = array();
|
|
|
|
|
+ $emailSet = array();
|
|
|
|
|
+ $numphoneSet = array();
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($queue as $row)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!empty($row['address']))
|
|
|
|
|
+ {
|
|
|
|
|
+ $addressSet[$row['address']] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!empty($row['email']))
|
|
|
|
|
+ {
|
|
|
|
|
+ $emailSet[$row['email']] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!empty($row['numphone']))
|
|
|
|
|
+ {
|
|
|
|
|
+ $numphoneSet[$row['numphone']] = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $queue = array(); // 清空当前层,准备下一层
|
|
|
|
|
+
|
|
|
|
|
+ // 构建合并后的查询条件
|
|
|
|
|
+ $conditions = array();
|
|
|
|
|
+ foreach (array_keys($addressSet) as $addr)
|
|
|
|
|
+ {
|
|
|
|
|
+ $conditions[] = "address like '%" . $this->db->escape_like_str($addr) . "%'";
|
|
|
|
|
+ }
|
|
|
|
|
+ foreach (array_keys($emailSet) as $em)
|
|
|
|
|
+ {
|
|
|
|
|
+ $conditions[] = "email like '%" . $this->db->escape_like_str($em) . "%'";
|
|
|
|
|
+ }
|
|
|
|
|
+ foreach (array_keys($numphoneSet) as $np)
|
|
|
|
|
+ {
|
|
|
|
|
+ $conditions[] = "numphone like '%" . $this->db->escape_like_str($np) . "%'";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (empty($conditions))
|
|
|
|
|
+ {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 一次查询获取所有匹配记录
|
|
|
|
|
+ $where = implode(' or ', $conditions);
|
|
|
|
|
+ $rows = $this->customer->find_all($where, $fields);
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($rows as $row)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!isset($child[$row['id']]))
|
|
|
|
|
+ {
|
|
|
|
|
+ $child[$row['id']] = $row;
|
|
|
|
|
+ $queue[] = $row; // 新发现的节点加入下一层搜索
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $child;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|