银狐营销系统银狐电销系统开发介绍和核心代码分享
银狐营销系统开发前言:
前半截是系统需求和架构思路,后半截是客户数据核心处理类库,欢迎大家和我一起做技术开发探讨,客户数据营销系统程序开发交流欢迎多交流,李铁牛 15889726201 微信同号1
每个业务性质的公司,聘请了业务员打营销电话,但是这些电话数据企业是通过各种通收集的,最终会汇集成表格然后分发给公司的营销部门做电话访问营销,但是会出现如下企业问题
业务痛点
1.数据遗漏,如果有大量的成千上万的客户数据需要分配给公司很多业务员跟进,那么这是一个很大的工作量,而且数据没有做好报表管理,客户数据容易遗漏掉
2.业务水平差异,业务员可能有老员工,新员工,每个人的电话营销经验不一样,每天跟进的客户数据也会不一样
3.客户数据质量差异,客户数据有优质数据普通数据,优质数据需要多分配个优秀的业务员跟进,给新手业务员数据就少分配一部分,这样子有利于客户回访质量
4.客户数据质量偶然性,意向客户数据各种各样,如果按照表格里的顺序一段一段地分析,那么可能某一段的客户数据是高质量的准客户,某一段客户数据不是意向度很强的数据,如果死板地这样分析,这样子也会影响业务员的客户访问效果。
5.客户数据泄露,每个业务员手头都有大量的客户数据,很有可能把数据通过各种形式带出公司出私单,甚至把客户数据卖给对手公司,这里我郑重提醒大家,倒卖公民信息数据是违法的!!!这样的行为将会给公司造成很大的潜在隐患
解决方案:
1.数据通过华企网通李铁牛开发的系统上传到系统数据中心
2.数据清洗,银狐营销系统对无效数据做识别剔除,对数据信息做汇总入库标准化到管理系统里
3.提供数据多样性多维度的检索
4.分配数据策略,对数据分配系统做灵活配置,通过给业务员组给出不同的比值权重分配数据,
例如按照平均数据分配;优秀业务和普通业务按照在系统里我们自定义的各种百分比方式分配
5.对优质数据公平分配,系统对客户数据队列打散重组,这样子每个业务员都有机会得到一样的客户数据质量。
6.数据上传完既焚,数据是企业的资产资源,这样子防止数据泄漏
7.业务员用的数据平台不提供批量数据预览
a.不提供数据检索列表,业务员只能看到1条待访问的客户数据
b.不提供分配的数据总数,数据总数没必要显示,防止业务员分心,数据总数信息企业也是很敏感的
c.进入系统既可看到要访问的单条数据
d.数据访问完毕,自动进入下一条待访问的客户数据
e.对访问过的客户数据做数据访问记录,例如:根据情况,访问时间点
f.访问数据预警,如果当前业务员的要访问的客户数据少于系统设定例如10条,系统给出存量提示
8.客户数据安全策略
a.系统是华企网通李铁牛自己开发架构,稳定可靠
b.数据源文件上传完就自焚,放在在服务器缓存大量的记录被窃用;
c.系统里的客户数据资料提供指令快捷一键删除;
d.系统提供定时自焚功能,如果用完需要保留那么久进入CMS中心里,如果用完既可,那么就按照设定的自焚程序清空。
银狐营销系统程序架构
标准的MVC模式架构
数据查询和读取缓存优化,同时支持文件缓存和Redis缓存
数据校验唯,系统唯一入口访问登陆和安全策略判断,
程序代码架构采用MAC方式来运行, M (module 系统某个模型),A (action 程序执行文件),C(collect 程序块某个方法)
类库函数库插件库逻辑位置合理划分
以下是银狐营销系统客户数据跟进核心代码类
1 <?php 2 defined(\'IN_KELE\') or exit(\'Access Denied\'); 3 class telephone 4 { 5 var $fields; 6 var $db; 7 var $table; 8 var $proid; 9 var $errmsg; 10 var $CFG; 11 12 //初始化数据和定义可存储数据字段 13 function __construct() 14 { 15 global $db, $CFG; 16 $this->db = $db; 17 $this->table = $db->pre . \'telephone\'; 18 $this->CFG = $CFG; 19 $this->fields = array(\'cusid\', \'telephone\', \'fullname\', \'areaname\', \'belong\', \'status\', \'del\', \'addtime\'); 20 } 21 22 //对$_POST值进行校验验证 23 function pass($post) 24 { 25 if (!is_array($post)) return $this->err(\'数据提交异常\'); 26 if (!isset($post[\'fullname\'])) return $this->err(\'请输入客户姓名\'); 27 if (!isset($post[\'telephone\'])) return $this->err(\'请输入客户电话\'); 28 return true; 29 } 30 31 //值做数据存储初始化 32 function set($post) 33 { 34 if (!is_array($post)) return $this->err(\'数据提交异常\'); 35 return array_map("trim", $post); 36 37 } 38 39 //更新数据 40 function edit($post) 41 { 42 $post_fields = $this->fields; 43 $post_sql = \'\'; 44 $post_sqlk = $post_sqlv = \'\'; 45 46 foreach ($post as $k => $v) { 47 if (in_array($k, $post_fields)) $post_sql .= ",$k=\'$v\'"; 48 } 49 $post_sql = substr($post_sql, 1); 50 $this->db->query("UPDATE {$this->table} SET $post_sql WHERE proid=$this->proid"); 51 $cat[\'proid\'] = $this->proid; 52 return true; 53 54 } 55 56 57 //非常重要的一个参数$admin, 58 function delete($post, $admin = FALSE) 59 { 60 if (!is_array($post)) { 61 return $this->err(\'您没有选择删除条件\'); 62 } 63 $cusid = isset($post[\'cusid\']) ? $post[\'cusid\'] : 0;//电销数据ID,以逗号为间隔 64 if (!$cusid) {return $this->err(\'您没有选择删除条件\');} 65 $fromtime = isset($post[\'fromtime\']) ? $post[\'fromtime\'] : 0; 66 $totime = isset($post[\'totime\']) ? $post[\'totime\'] : 0; 67 $condition = \' 1=1 \'; 68 if ($cusid){ 69 $condition .= ($cusid != \'all\') ? " and cusid in ({$cusid})" : \' \';//一键清空判断 70 } 71 if ($fromtime && $totime) { 72 if ($fromtime <= $totime) { 73 $condition .= " and addtime>=\'{$fromtime}\'"; 74 $condition .= " and addtime<=\'{$totime}\'"; 75 } 76 } 77 $sql = "UPDATE {$this->table} SET del=\'1\' WHERE {$condition}"; 78 if ($this->db->query($sql)) { 79 $count = $this->db->affected_rows(); 80 if ($count) { 81 $this->errmsg = "{$count}条记录删除成功"; 82 return true; 83 } else { 84 $this->errmsg = "0条记录被删除"; 85 return false; 86 } 87 } else { 88 return $this->err(\'删除失败!当前要删除的记录不存在\'); 89 } 90 } 91 92 //清理回收站内容 93 function clear($cusid, $admin = FALSE) 94 { 95 $condition = ($cusid != \'all\') ? " and cusid in ({$cusid})" : \' \';//一键清空判断 96 $sql = "DELETE FROM {$this->table} WHERE del=1 {$condition}"; 97 $this->db->query($sql); 98 $count = $this->db->affected_rows(); 99 return $count; 100 } 101 102 //恢复回收站数据 103 function recovery($cusid, $admin = FALSE) 104 { 105 $sql = "UPDATE {$this->table} SET del=0 WHERE del=1 and cusid in({$cusid})"; 106 $this->db->query($sql); 107 $count = $this->db->affected_rows(); 108 return $count; 109 } 110 111 112 //产品属性添加 113 function attAdd($proid, $att) 114 { 115 $att = explode(\',\', $att);//把属性字符串设置为数组 116 $sql = "SELECT proid,attid FROM {$this->db->pre}products WHERE proid in($proid)"; 117 $result = $this->db->query($sql); 118 $count = 0; 119 while ($row = $this->db->fetch_array($result)) { 120 $rowAtt = explode(\',\', $row[\'attid\']); 121 $attid = array_unique(array_merge($att, $rowAtt)); 122 $attid = implode(\',\', $attid); 123 $this->db->query("UPDATE {$this->db->pre}products SET attid=\'{$attid}\' WHERE proid={$row[\'proid\']}"); 124 $count++; 125 } 126 return $count; 127 } 128 129 function attDel($proid, $att) 130 { 131 $att = explode(\',\', $att);//把属性字符串设置为数组 132 $sql = "SELECT proid,attid FROM {$this->db->pre}products WHERE proid in($proid)"; 133 $result = $this->db->query($sql); 134 $count = 0; 135 while ($row = $this->db->fetch_array($result)) { 136 $rowAtt = explode(\',\', $row[\'attid\']); 137 $attid = str_replace($att, array(), $rowAtt); 138 $attid = implode(\',\', array_filter($attid)); 139 $this->db->query("UPDATE {$this->db->pre}products SET attid=\'{$attid}\' WHERE proid={$row[\'proid\']}"); 140 $count++; 141 } 142 return $count; 143 }
234 function proidBatchCat($proid, $catid) 235 { 236 $sql = "UPDATE {$this->table} SET catid=\'{$catid}\' WHERE proid in({$proid})"; 237 $result = $this->db->query($sql); 238 $count = $this->db->affected_rows(); 239 return $count; 240 } 241 242 243 function get_one($proid = \'\') 244 { 245 return $this->db->get_one("SELECT * FROM {$this->table} WHERE proid=\'{$this->proid}\'"); 246 } 247 248 249 function listinfo($condition, $order = \'cusid asc\') 250 { 251 global $pages, $page, $pagesize, $offset, $catArr, $CFG, $catTaoArr, $catTaoMainArr; 252 $items = $this->db->count("{$this->table}", $condition); 253 $pages = pages($items, $page, $pagesize); 254 $result = $this->db->query("SELECT * from {$this->table} WHERE $condition order by {$order} LIMIT {$offset},{$pagesize}"); 255 $lists = array(); 256 while ($row = $this->db->fetch_array($result)) { 257 $memberArr = memberInfo($row[\'username\']); 258 $row[\'memberFullname\'] = $memberArr ? $memberArr[\'fullname\'] : \'\'; 259 $lists[] = $row; 260 } 261 return $lists; 262 } 263 function telephoneImport($filename){ 264 global $KL_TIME; 265 $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); 266 if ($extension == \'xlsx\') { 267 PHPExcel_IOFactory::createReader(\'Excel2007\', \'utf-8\'); 268 $objPHPExcel = PHPExcel_IOFactory::load($filename); 269 270 } else { 271 //判断是否是xls老版本 , 272 $xlsReader = PHPExcel_IOFactory::createReader(\'Excel5\'); 273 $objPHPExcel = $xlsReader->load($filename); 274 } 275 $currentSheet = $objPHPExcel->getSheet(0); 276 $highestRow = $currentSheet->getHighestRow(); // 取得总行数 277 $highestColumn = $currentSheet->getHighestColumn(); // 取得总列数 278 $areanameField = $objPHPExcel->getActiveSheet()->getCell("B1")->getValue(); 279 $fullnameField = $objPHPExcel->getActiveSheet()->getCell("C1")->getValue(); 280 $telephoneField = $objPHPExcel->getActiveSheet()->getCell("D1")->getValue(); 281 $AreaField = $objPHPExcel->getActiveSheet()->getCell("E1")->getValue(); 282 283 if (($areanameField == \'楼盘\') && ($fullnameField == \'姓名\') && ($telephoneField == \'电话\')) { 284 $insertBatSql=\'\'; 285 $count= 0; 286 for ($j = 2; $j <= $highestRow; $j++) { 287 $areaname = $objPHPExcel->getActiveSheet()->getCell("B" . $j)->getValue(); 288 $fullname = $objPHPExcel->getActiveSheet()->getCell("C" . $j)->getValue(); 289 $telephone = $objPHPExcel->getActiveSheet()->getCell("D" . $j)->getValue(); 290 $area = $objPHPExcel->getActiveSheet()->getCell("E" . $j)->getValue(); 291 $areaname = trim($area) ? "{$area} . {$areaname}" : $areaname; 292 if($telephone==\'\') continue; 293 $insertBatSql.=" (\'{$areaname}\', \'{$fullname}\', \'{$telephone}\',\'{$KL_TIME}\') ,"; 294 } 295 if($insertBatSql){ 296 $insertBatSql=rtrim($insertBatSql,\',\');//去除最后一个逗号 297 $insertBatSql="INSERT INTO {$this->db->pre}telephone(areaname, fullname, telephone, addtime) VALUES {$insertBatSql}"; 298 $this->db->query($insertBatSql); 299 $count = $this->db->affected_rows(); 300 } 301 $errTel = $highestRow-$count; 302 $this->errmsg = "<div class=\'box-body\'>上传总数据记录是<label class=\' text-yellow\'> {$highestRow} </label>条<br>过滤掉<label class=\'text-red\'> {$errTel} </label>条无效数据,<br>成功入库<label class=\'text-green\'> {$count} </label>条有效客户数据</div>"; 303 //exit($this->errmsg ); 304 return true; 305 } else { 306 return $this->err("上传的客户名单模板错误,请核实,要求的excel第一列格式必须为 【序号】【楼盘】【姓名】【电话】"); 307 } 308 } 309 310 //$ratio 分配参数,判断分配策略是否满足条件 311 function allot($ratio){ 312 $total = $this->db->count($this->table , "username is null"); //总记录条数 313 $memberTotal = $this->db->count($this->db->pre . \'member\' , "status=\'1\'"); //正常会员数 314 $memberOneTotal = $this->db->count($this->db->pre . \'member\' , "status=\'1\' AND level=\'1\'");//黄金会员 315 $memberTwoTotal = $this->db->count($this->db->pre . \'member\' , "status=\'1\' AND level=\'2\'");//钻石会员 316 $memberLevel =$this->CFG[\'memberLevel\']; 317 $ratioArr = $this->CFG[\'ratioData\'];//读取数据分配比率 318 if(!array_key_exists($ratio,$ratioArr)){ 319 $data[\'code\']=\'0\'; 320 exit(jsonChinese($data)); 321 } 322 $abc=explode(\':\',$ratioArr[$ratio]); 323 $a = $abc[0]; 324 $b = $abc[1]; 327 $oneCount = intval($total/($memberOneTotal*($a/$b)+$memberTwoTotal)*($a/$b)); 328 $twoCount = intval($total/($memberOneTotal*($a/$b)+$memberTwoTotal)); 330 $oneTips=$oneCount<1?\'小于1\':$oneCount; 331 $twoTips=$twoCount<1?\'小于1\':$twoCount; 332 if($oneCount&&$twoCount){ 333 $data[\'code\'] = \'1\'; 334 $data[\'oneCount\'] = $oneCount; 335 $data[\'twoCount\'] = $twoCount; 336 $data[\'msg\'] = "{$memberLevel[1]}人均数据量:<span class=\'text-red\'>{$oneTips}</span>,{$memberLevel[2]}人均数据量:<span class=\'text-red\'>{$twoTips}</span>"; 337 } 338 else{ 339 $data[\'code\'] = \'0\'; 340 $data[\'msg\'] = "数据分配失败,系统测算分配的数据不足!<br><br>{$memberLevel[1]}人均数据量:<span class=\'text-red\'>{$oneTips}</span>,{$memberLevel[2]}人均数据量:<span class=\'text-red\'>{$twoTips}</span>"; 341 } 342 $data[\'total\'] = $total; 343 $data[\'memberTotal\'] = $memberTotal; 344 $data[\'memberOneTotal\'] = $oneCount; 345 $data[\'memberTwoTotal\'] = $twoCount; 346 return $data; 347 } 348 349 function allotOk($ratio){ 350 $data = $this->allot($ratio); 351 if($data[\'code\']){ 352 $memberOneTotal = $data[\'memberOneTotal\']; 353 $memberTwoTotal = $data[\'memberTwoTotal\']; 354 $result = $this->db->query("SELECT username,level FROM {$this->db->pre}member WHERE status=1 ORDER BY level desc,userid asc "); 355 $count = $this->db->count("{$this->db->pre}member"," status=1"); 356 $i=1; 357 while ($row = $this->db->fetch_array($result)) { 358 $total = ($row[\'level\']==\'1\')?$memberOneTotal:$memberTwoTotal; 359 $limit = ($i==$count) ? \'\':" limit {$total}"; 360 $sql = "UPDATE {$this->table} SET username=\'{$row[\'username\']}\' WHERE username is NULL ORDER BY rand() {$limit}"; 361 $i++; 362 $this->db->query($sql); 363 } 364 $this->errmsg =$data[\'msg\']; 365 return true; 366 } 367 else{ 368 return $this->err($data[\'msg\'] ); 369 } 370 } 371 372 function follow($username){ 373 $sql = "SELECT * FROM {$this->table} WHERE username=\'{$username}\'AND followtime=0 AND del=0 order by cusid asc limit 1"; 374 $cus = $this->db->get_one($sql); 375 if($cus){ 376 $cus[\'telephone\'] = preg_replace(\'/\s+/\',\'\',$cus[\'telephone\']); 377 preg_match(\'/([\d]{3})([\d]{4})([\d]{4})/\', $cus[\'telephone\'] , $match); 378 unset($match[0]); 379 $cus[\'telephone\'] = implode(\' \', $match); 380 $cus[\'code\']=1; 381 } 382 else{ 383 $cus[\'code\'] = 0; 384 $cus[\'info\'] = \'已经没有需要未跟进的客户数据了\';//具体错误信息 385 } 386 return $cus; 387 } 388 389 function err($error) 390 { 391 $this->errmsg = $error; 392 return false; 393 } 394 }
银狐营销系统开发相关介绍就到这里,以上内容是关于银狐电销系统开发的一些技术架构小结,电销系统技术开发欢迎多交流,李铁牛 微信号:15889726201