<?php
/**
  * @method API统计
  * @author soul
  * @copyright 2018/10/31
  */
class PjltjMain extends PjltjBase
{
	public $adsMinDate = null;
	public $hasAdsShowUids = [];

	/**
	  * @method 根据token分析是否可以继续请求 
				1、无token，ip+from+devcode+apiFun 10分钟内不超过 300 次
				2、有token，uid+from+apiFun 10分钟内不超过 300 次
	  * @param  $tokenInfo ["uid":149894,"devcode":"c905b218685c253c66315d61e95d6350","from":"PJD","token":"a5015bf0863845a8c81ab52f4e3781da"]
	  * @param  $apiFun 接口名称 'base/login'
	  * @author soul
	  * @copyright 2016/3/30
	  * @return array(3) { ["status"]=> bool(true) ["data"]=> ['count'=>200]  ["code"]=> int(0) } 
	  */
	public function onlyCheckMonitor($actName, $dataArr)
	{
		if(!isset(mvc::$cfg['RABBIT']['act'][$actName])) return LibFc::ReturnData(false, $actName.'参数act不存在！');
		$arr = ['pass'=>0, 'tj'=>0, 'msg'=>'', 'code'=>'']; 
		$max = 300; $perTime = 600; $now = time(); 
		switch($actName)
		{
			case 'TJ_MAIN':
				$res = $this->getTjReg();
				$tjRegArr = $res['data'];
				$uact = trim(strtoupper($dataArr['tj_act']));
				if(!empty($tjRegArr[$dataArr['tj_site']][$uact]))
				{
					//ip是否被限制
					$res = $this->get('tj_blacklist', ['bl_id'], sprintf(" and bl_etime >= %d and bl_ip='%s' and bl_uid = 0", $now, LibFc::Escape($dataArr['tj_ip'])), true);
					if(!empty($res['data']))
						return LibFc::ReturnData(true, ['pass'=>0, 'tj'=>0, 'msg'=>'网络访问受限！', 'code'=>'IP']);

					//ip段是否被限制
					$tip = explode('.', $dataArr['tj_ip']);
					$ip3 = $tip[0].'.'.$tip[1].'.'.$tip[2].'.';
					$res = $this->get('tj_blacklist', ['bl_id'], sprintf(" and bl_etime >= %d and bl_ip ='%s' AND bl_site='%s' AND bl_apiact='%s' and bl_uid = 0", $now, LibFc::Escape($ip3), LibFc::Escape($dataArr['tj_site']), LibFc::Escape($dataArr['tj_act'])), true);
					if(!empty($res['data']))
						return LibFc::ReturnData(true, ['pass'=>0, 'tj'=>0, 'msg'=>'网络访问受限！', 'code'=>'IP']);

					//账号是否受限
					if(!empty($dataArr['tj_uid']))
					{
						$res = $this->get('tj_blacklist', ['bl_id'], sprintf(" and bl_etime >= %d and bl_uid=%d and bl_apiact=''", $now, $dataArr['tj_uid']), true);
						if(!empty($res['data'])) 
							return LibFc::ReturnData(true, ['pass'=>0, 'tj'=>0, 'msg'=>'账号访问受限！', 'code'=>'USER']);

						//接口访问受限
						if(!empty($dataArr['tj_act']))
						{
							$res = $this->get('tj_blacklist', ['bl_id'], sprintf(" and bl_etime >= %d and bl_uid=%d and bl_apiact='%s'", $now, $dataArr['tj_uid'], LibFc::Escape($dataArr['tj_act'])), true);
							if(!empty($res['data'])) 
								return LibFc::ReturnData(true, ['pass'=>0, 'tj'=>0, 'msg'=>'此功能访问受限，您可以入驻跑街令继续查询或者明天再来！', 'code'=>'pjlShop']);
						}
					}
					$arr['tj'] = 1;
				}
			break;
		}
		$arr['pass'] = 1;
		return LibFc::ReturnData(true, $arr);
	}


	/**
	  * @method 获取统计的限制规则
	  * @param $cache  是否直接取缓存
	  * @author soul
	  * @copyright 2020/1/16
	  * @return 
	  */
	public function getTjReg($cache = true)
	{
		$apiActReg = [];
		$file = mvc::$cfg['AUTOLOAD']['Pjltj']['path'].'cache/tjActReg.php';
		if(!file_exists($file) || !$cache || filemtime($file) < (time()-1800))
		{
			$res = $this->get('at_tongji_reg', ['*'], ' order by tr_seq');
			foreach($res['data'] as $v)
			{
				$v['tr_act_unival'] = empty($v['tr_act_unival'])? []: explode(':', $v['tr_act_unival']);
				$apiActReg[$v['tr_site']][trim(strtoupper($v['tr_act']))] = $v;
			}
			LibFc::ArraySave($apiActReg, $file);
		}
		else
		{//括起来为了防止读取文件失败
			$apiActReg = include($file);
			if(!is_array($apiActReg) || !is_array($apiActReg['PJL'])){
				@unlink($file);
				return $this->getTjReg(false);
			}
		}
		return LibFc::ReturnData(true, $apiActReg);
	}


	/**
	  * @method 通过统计数据计算当天的限制对象
	  * @author soul
	  * @copyright 2016/3/30
	  * @return 
		1、当日某接口超额，停止此接口当日访问
		2、某用户同一个接口最近4天有3天触发限制，封账号
		3、最近2天 同IP同一个接口下有5个账号被封则封IP 5天，并将封账号
		3、最近1天 同IP下有5个账号被封则封IP 30天，并将封账号
	  */
	public function buildTjApiBlack() 
	{
		$now = time();
		$todayB = strtotime(date('Y-m-d'));
		$today = date('Ymd');

		$res = $this->getTjReg(false);
		$apiActReg = $res['data'];

		$YpwBase = new YpwBase();
		$PjlBase = new PjlBase();
		
		//付费商家ID
		$twhere = sprintf(" AND shop_status = 2 AND shop_vip_etime > %d", $now);
		$res = $PjlBase->get('pl_shop', ['shop_pu_id'], $twhere);
		$payUserArr = array_column($res['data'], 'shop_pu_id');
		
		//白名单
		$res = $this->get('tj_whitelist', ['distinct wl_uid'], sprintf(" and wl_uid > 0 and wl_etime > %d and wl_type = 'user'", $now));
		$whiteArr = array_column($res['data'], 'wl_uid');
		
		//单接口 哪些用户超标了
		$addApiBlack = [];
		foreach($apiActReg as $site=>$sitev)
		{
			foreach($sitev as $rv)
			{
				if($rv['tr_max_count_user'] < 1 || empty($rv['tr_act_unival'])) continue;

				$uniFiled = [];
				foreach($rv['tr_act_unival'] as $uf)
				{
					$uniFiled[] = sprintf("JSON_UNQUOTE(tj_param->'$.%s')", $uf);
				}
				$uniFiled = implode(",'@',", $uniFiled);

				//APP端
				$where = sprintf(" and tj_uid > 0 and tj_site='%s' and tj_act='%s' and tj_time >=%d and tj_from not in ('PJLPC', 'PJDSUPER', 'PJLSOFT') group by tj_uid having val_count >= %d", $site, LibFc::Escape($rv['tr_act']), $todayB, $rv['tr_max_count_user']);

				//已经在黑名单的用户
				$res = $this->get('tj_blacklist', ['distinct bl_uid'], sprintf(" and bl_uid > 0 and bl_etime > %d and (bl_apiact='%s' or bl_apiact='')", $now, LibFc::Escape($rv['tr_act'])));
				if(!empty($res['data'])) $where .=  sprintf(" and tj_uid not in (%s)", implode(',', array_column($res['data'], 'bl_uid')));

				$ares = $this->get('at_tongji', ['tj_uid, tj_ip, tj_devcode, count(distinct CONCAT('.$uniFiled.')) as val_count'], $where);
				if(empty($ares['data'])) continue;
				foreach($ares['data'] as $vv)
				{	
					//付费商家但是尚未触碰商家限额
					if(in_array($vv['tj_uid'], $payUserArr) && $vv['val_count'] < $rv['tr_max_count_pay']) continue;
					$addApiBlack[] = [
						'bl_type'=>'userapi',
						'bl_adate'=>date('Ymd'),
						'bl_uid'=>$vv['tj_uid'],
						'bl_ip'=>$vv['tj_ip'],
						'bl_devcode'=>$vv['tj_devcode'],
						'bl_site'=>$site,
						'bl_apiact'=>$rv['tr_act'],
						'bl_atime'=>$now,
						'bl_etime'=>strtotime(date('Y-m-d 23:59:59')),
						'bl_remark'=>$rv['tr_act_name'].'查询'.$vv['val_count'].'次达到最高限制'
					];
					
				}
			}
		}
		
		$this->TjDb->Begin();

		if(!empty($addApiBlack)) $this->addAny('tj_blacklist', array_keys($addApiBlack[0]), $addApiBlack);

		//用户最近10天有7天触发限制，限制账号
		$where = sprintf(" and bl_type='userapi' and bl_atime >=%d and bl_uid not in (
			select distinct bl_uid from tj_blacklist where bl_etime > %d and bl_type='user'
		)  GROUP BY bl_uid, bl_apiact HAVING bcount >= 7", strtotime('-10 day'), $now);
		$res = $this->get('tj_blacklist JOIN at_tongji_reg ON tr_act = bl_apiact and tr_site=bl_site', ['bl_uid, bl_ip, bl_devcode, bl_site, bl_apiact, tr_act_name, COUNT(DISTINCT bl_adate) AS bcount'], $where);
		foreach($res['data'] as $tv)
		{
			if(in_array($tv['bl_uid'], $whiteArr)) continue;
			$addArr = [
				'bl_type'=>'user',
				'bl_adate'=>date('Ymd'),
				'bl_uid'=>$tv['bl_uid'],
				'bl_ip'=>$tv['bl_ip'],
				'bl_devcode'=>$tv['bl_devcode'],
				'bl_site'=>$tv['bl_site'],
				'bl_apiact'=>$tv['bl_apiact'],
				'bl_atime'=>$now,
				'bl_etime'=>strtotime('+10 years'),
				'bl_remark'=>$tv['tr_act_name'].'访问异常限制账号'
			];
			$this->add('tj_blacklist', $addArr);
			//封账号
			$YpwBase->Set('yp_user', ['u_status'=>'-2', 'u_status_remark'=>'跑街令访问异常，'.$tv['tr_act_name'].'访问异常限制账号'], sprintf(" and u_id =%d and u_status = 1", $tv['bl_uid']));
		}

		//最近2天 同IP有5个账号被限制则封IP 5天
		$where = sprintf(" and bl_ip != '' and bl_atime >=%d and bl_ip not in (
			select distinct bl_ip from tj_blacklist where bl_etime > %d and bl_type='ip'
		) group by bl_ip, bl_site having bcount >= 5", strtotime('-2 day'), $now);
		$res = $this->get('tj_blacklist', ['bl_ip, bl_site, bl_apiact, count(distinct bl_uid) as bcount'], $where);
		foreach($res['data'] as $tv)
		{
			$addArr = [
				'bl_type'=>'ip',
				'bl_adate'=>date('Ymd'),
				'bl_ip'=>$tv['bl_ip'],
				'bl_site'=>$tv['bl_site'],
				'bl_atime'=>$now,
				'bl_etime'=>strtotime('+5 day'),
				'bl_remark'=>'最近多个账号异常限制IP'
			];
			$this->add('tj_blacklist', $addArr);
		}
		
		//根据IP限制
		$addApiBlack = [];
		foreach($apiActReg as $site=>$sitev)
		{
			foreach($sitev as $rv)
			{
				if($rv['tr_max_count_ip'] < 1 || empty($rv['tr_act_unival'])) continue;

				//APP端
				$where = sprintf(" and tj_uid = 0 and tj_site='%s' and tj_act='%s' and tj_time >=%d and tj_from not in ('PJLPC', 'PJDSUPER', 'PJLSOFT') group by tj_ip having val_count >= %d", $site, LibFc::Escape($rv['tr_act']), $todayB, $rv['tr_max_count_ip']);

				//已经在黑名单的用户
				$res = $this->get('tj_blacklist', ['distinct bl_ip'], sprintf(" and bl_etime > %d and (bl_apiact='%s' or bl_apiact='')", $now, LibFc::Escape($rv['tr_act'])));
				if(!empty($res['data'])) $where .=  sprintf(" and tj_ip not in ('%s')", implode("','", array_column($res['data'], 'bl_ip')));

				$ares = $this->get('at_tongji', ['tj_ip, count(*) as val_count'], $where);
				if(empty($ares['data'])) continue;
				foreach($ares['data'] as $vv)
				{	
					$addArr = [
						'bl_type'=>'ip',
						'bl_adate'=>date('Ymd'),
						'bl_ip'=>$vv['tj_ip'],
						'bl_site'=>$site,
						'bl_apiact'=>$rv['tr_act'],
						'bl_atime'=>$now,
						'bl_etime'=>strtotime('+2 day'),
						'bl_remark'=>'非登录'.$rv['tr_act_name'].'查询'.$vv['val_count'].'次达到最高限制'
					];
					$this->add('tj_blacklist', $addArr);
				}
			}
		}

		//黑名单用户
		$blackUidArr = [];

		//>3账号同IP，并且在接口限制名单里
		//受接口管控的账号
		$where = sprintf(" and bl_adate = '%d' AND bl_type = 'userapi' AND bl_uid NOT IN (SELECT bl_uid FROM tj_blacklist WHERE bl_type = 'user' and bl_etime > %d)",
			$today, $now);
		$res = $this->get('tj_blacklist', ['bl_uid'], $where);
		if(!empty($res['data']))
		{
			$sxUids = array_column($res['data'], 'bl_uid');
			//当天用户IP关系
			$res = $this->get('at_tongji', ['tj_uid, tj_ip'], sprintf(" and tj_uid in (%s) and tj_date=%d group by tj_uid, tj_ip", implode(",", $sxUids), $today));
			$ipUidArr = [];
			$uidIpArr = [];
			foreach($res['data'] as $tv)
			{
				$ipUidArr[$tv['tj_ip']][$tv['tj_uid']] = $tv['tj_uid'];
				$uidIpArr[$tv['tj_uid']][$tv['tj_ip']] = $tv['tj_ip'];
			}

			foreach($ipUidArr as $ip=>$uids)
			{
				//同ip 4个账号以上
				if(count($uids) > 3)
				{
					$isBlack = false;
					foreach($uids as $uid)
					{
						//此账号IP数也达到5个
						if(count($uidIpArr[$uid]) > 4)
						{
							$isBlack = true;
						}
						else
						{
							//这个账号的其他IP也同时存在多个账号
							foreach($uidIpArr[$uid] as $ip2)
							{
								if($ip != $ip2 && count($ipUidArr[$ip2]) > 3)
								{
									$isBlack = true;
									break;
								}
							}
						}
						if($isBlack) break;
					}
					
					if($isBlack)
					{
						foreach($uids as $uid)
						{
							$blackUidArr[$uid] = $ip;
						}
					}
				}
			}
		}

		//同IP 访问限制接口 >3账号
		$where = sprintf(" and tj_date ='%d' and tj_act in ('data/decodeVin', 'search/vin')  AND tj_uid > 0 AND tj_from IN ('PJLIOS', 'PJLAND','PJD') GROUP BY tj_ip HAVING COUNT(DISTINCT tj_uid) > 3", $today);
		$table = 'at_tongji JOIN at_tongji_reg ON tr_act = tj_act and tr_max_count_user > 0';
		$res = $this->get($table, ['tj_ip ip, GROUP_CONCAT(DISTINCT tj_uid) uids'], $where);
		if(!empty($res['data']))
		{
			$ipUserArr = [];
			$uids = [];
			foreach($res['data'] as $v)
			{
				$ipUserArr[$v['ip']] = explode(',', $v['uids']);
				$uids = array_merge($uids, $ipUserArr[$v['ip']]);
			}
			$uids = array_values(array_unique($uids));
			
			//这些用户的ip记录
			$where = sprintf(" and tj_date ='%d' and tj_act in ('data/decodeVin', 'search/vin') AND tj_uid in (%s) AND tj_from IN ('PJLIOS', 'PJLAND','PJD') GROUP BY tj_uid HAVING COUNT(DISTINCT tj_ip) > 3", $today,  implode(',', $uids));
			$table = 'at_tongji JOIN at_tongji_reg ON tr_act = tj_act and tr_max_count_user > 0';
			$res = $this->get($table, ['tj_uid uid, GROUP_CONCAT(DISTINCT tj_ip) ips'], $where);
			$userIpArr = [];
			foreach($res['data'] as $v)
			{
				$userIpArr[$v['uid']] = explode(',', $v['ips']);
			}

			//开始比较
			foreach($ipUserArr as $ip=>$uids)
			{
				$cxCount = 0;
				$hascomuips = [];
				foreach($uids as $uid)
				{
					if(!empty($blackUidArr[$uid]) || empty($userIpArr[$uid])) continue;
					foreach($userIpArr[$uid] as $uip)
					{
						if(empty($ipUserArr[$uip]) || $ip == $uip || in_array($uip, $hascomuips)) continue;
						$hascomuips[] = $uip;
						$sameUids = array_intersect($uids, $ipUserArr[$uip]);
						//相同率大于50%
						if(count($sameUids) > 3 && count($sameUids) / count($uids) > 0.5)
						{
							$cxCount++;
						}
					}
				}
				//封此IP下的所有用户
				if($cxCount > 2)
				{
					foreach($uids as $uid)
					{
						$blackUidArr[$uid] = $ip;
					}
				}
			}
		}
		if(!empty($blackUidArr))
		{
			$where = sprintf(" and bl_type = 'user' and bl_uid in (%s) and bl_etime > %d", implode(',', array_keys($blackUidArr)), $now);
			$res = $this->get('tj_blacklist', ['bl_uid'], $where);
			$hasBlackUser = array_column($res['data'], 'bl_uid');
			foreach($blackUidArr as $uid=>$ip)
			{
				if(in_array($uid, $whiteArr)) continue;
				if(in_array($uid, $hasBlackUser)) continue;
				if(in_array($uid, $payUserArr)) continue;
				//最近PV低于100
				$res = $this->get('at_tongji', ['count(*) pv'], sprintf(" and tj_uid = %d and tj_act in ('data/decodeVin', 'search/vin')", $uid), true);
				if($res['data']['pv'] < 100) continue;

				$addArr = [
					'bl_type'=>'user',
					'bl_adate'=>date('Ymd'),
					'bl_uid'=>$uid,
					'bl_ip'=>$ip,
					'bl_atime'=>$now,
					'bl_etime'=>strtotime('+10 years'),
					'bl_remark'=>'跑街令访问异常，多账号多IP, 禁止解封'
				];
				$this->add('tj_blacklist', $addArr);
				//封账号
				$YpwBase->Set('yp_user', ['u_status'=>'-2', 'u_status_remark'=>'跑街令访问异常，多账号多IP, 禁止解封'], sprintf(" and u_id =%d and u_status = 1", $uid));
			}
		}
		
		//tcd非登陆用户封IP段
		$sql = sprintf("INSERT INTO `tj_blacklist`(bl_adate, bl_type, bl_ip, bl_atime, bl_etime, bl_site, bl_apiact, bl_remark)
		SELECT * FROM (
		SELECT '%s' bl_adate, 'ip' bl_type, CONCAT(SUBSTRING_INDEX(tj_ip, '.', 3), '.') bl_ip,  UNIX_TIMESTAMP() bl_atime, UNIX_TIMESTAMP(DATE_ADD(NOW(), INTERVAL 3 DAY)) bl_etime,
		'YP' bl_site, 'item/index' bl_apiact, CONCAT('非登录TCD详情封IP段，IP数：', COUNT(DISTINCT tj_ip), ' 查询数：', COUNT(*)) bl_remark FROM at_tongji 
		WHERE tj_date = '%s' AND tj_uid=0 AND tj_site='YP' AND tj_act='item/index' GROUP BY bl_ip HAVING COUNT(DISTINCT tj_ip) > 30
		) t WHERE CONCAT(bl_adate, bl_type, bl_ip, bl_site, bl_apiact) NOT IN (
		SELECT CONCAT(bl_adate, bl_type, bl_ip, bl_site, bl_apiact) FROM `tj_blacklist`
		)", $today, $today);
		$this->exeAnySql([$sql]);

		$this->TjDb->End();
		return LibFc::ReturnData(true, 'OK');
	}



	
	/**
	  * @method 主监控系统日统计生成  每小时一更新
	  * @author soul
	  * @copyright 2020/4/30
	  * @return 
	  */
	public function mainTongjiDate()
	{
		//查找上一次执行的最后日期
		$firstDate = '20190101';
		$res = $this->get('at_tongji_date', ['max(td_date) as td_date'], '', true);
		if(empty($res['data']['td_date']))
			$res = $this->get('at_tongji', ["min(tj_date) as td_date"], '', true);
		if(!empty($res['data']['td_date'])) 
			$firstDate = $res['data']['td_date'];

		$dateArr = [];
		$dateArr = array_map( function ($n) { return date('Ymd', $n);}, range(strtotime($firstDate), strtotime(date('Ymd')), 24 * 3600));
		asort($dateArr);

		//将数据转为统计格式  vin  number
		/*$formatSql  = [
			sprintf("UPDATE at_tongji,at_tongji_reg SET tj_param = JSON_SET(tj_param,'$.number', JSON_UNQUOTE(tj_param->'$.word')) WHERE tj_site = tr_site AND tr_act = tj_act AND tr_act_group = 'NUMBER' AND JSON_CONTAINS_PATH(tj_param,'one', '$.number') = 0 AND JSON_CONTAINS_PATH(tj_param,'one', '$.word') = 1"),	
			sprintf("UPDATE at_tongji,at_tongji_reg SET tj_param = JSON_SET(tj_param,'$.number', JSON_UNQUOTE(tj_param->'$.keyword')) WHERE tj_site = tr_site AND tr_act = tj_act AND tr_act_group = 'NUMBER' AND JSON_CONTAINS_PATH(tj_param,'one', '$.number') = 0 AND JSON_CONTAINS_PATH(tj_param,'one', '$.keyword') = 1")
		];
		$this->exeAnySql($formatSql);
		*/
		$lastTjDate = '';
		foreach($dateArr as $date)
		{
			$this->TjDb->Begin();
			$lastTjDate = $date;
		
			//清空最后日期的数据统计
			$this->del('at_tongji_date', ' and td_date = '.$date);
			//监控表
			$whereArr = [
				[
					'filed'=>["'all' as tj_site, 'all' as tj_act, 'all' as tj_from, count(distinct tj_ip) as ip_count,  count(distinct tj_devcode) as devcode_count, count(*) as pv_count, count(distinct tj_uid) as uid_count"],
					'where'=>sprintf(" and tj_date = %d group by tj_date", $date)
				],
				[
					'filed'=>["tj_site, 'all' as tj_act, 'all' as tj_from, count(distinct tj_ip) as ip_count,  count(distinct tj_devcode) as devcode_count, count(*) as pv_count, count(distinct tj_uid) as uid_count"],
					'where'=>sprintf(" and tj_date = %d group by tj_date, tj_site", $date)
				],
				[
					'filed'=>["tj_site, tj_act, 'all' as tj_from, count(distinct tj_ip) as ip_count,  count(distinct tj_devcode) as devcode_count, count(*) as pv_count, count(distinct tj_uid) as uid_count"],
					'where'=>sprintf(" and tj_date = %d group by tj_date, tj_site, tj_act", $date)
				],
				[
					'filed'=>["tj_site, tj_act, tj_from, count(distinct tj_ip) as ip_count,  count(distinct tj_devcode) as devcode_count, count(*) as pv_count, count(distinct tj_uid) as uid_count"],
					'where'=>sprintf(" and tj_date = %d group by tj_date, tj_site, tj_act, tj_from", $date)
				],
			];
			foreach($whereArr as $wv)
			{
				$tjRes = $this->get('at_tongji', $wv['filed'], $wv['where']);
				foreach($tjRes['data'] as $tk=>$tv)
				{
					$addArr = [
						'td_date'=>$date,
						'td_site'=>$tv['tj_site'],
						'td_act'=>$tv['tj_act'],
						'td_from'=>$tv['tj_from'],
						'td_ip_count'=>$tv['ip_count'],
						'td_devcode_count'=>$tv['devcode_count'],
						'td_pv_count'=>$tv['pv_count'],
						'td_uid_count'=>$tv['uid_count'],
					];
					$this->add('at_tongji_date', $addArr);
				}
			}
			$this->TjDb->End();
		}

		$this->TjDb->Begin();
		$delDate = date('Ymd',strtotime('-7 day'));
		//最近只保留7天的记录明细，其他的放到
		if($delDate < $lastTjDate)
		{
			$formatSql  = [
				sprintf("insert into at_tongji_all select * from at_tongji where tj_date <=%d", $delDate),	
				sprintf("delete from at_tongji where tj_date <=%d", $delDate)
			];
			$this->exeAnySql($formatSql);
		}
		$this->TjDb->End();
		return LibFc::ReturnData(true);
    }


	/**
	  * @method 用户数据日统计生成  每天一更新
	  * @author soul
	  * @copyright 2020/4/30
	  * @return 
	  */
	public function userTongjiDate()
	{
		//查找上一次执行的最后日期
		$firstDate = '20190101';
		$res = $this->get('at_user_date', ['max(ud_date) as td_date'], '', true);
		if(empty($res['data']['td_date']))
			$res = $this->get('at_tongji', ["min(tj_date) as td_date"], '', true);
		if(!empty($res['data']['td_date'])) 
			$firstDate = $res['data']['td_date'];

		$dateArr = [];
		$dateArr = array_map( function ($n) { return date('Ymd', $n);}, range(strtotime($firstDate), strtotime(date('Ymd')), 24 * 3600));
		asort($dateArr);

		$YpwBase = new YpwBase();
		$lastTjDate = '';
		foreach($dateArr as $date)
		{
			$this->TjDb->Begin();
			$lastTjDate = $date;
		
			//清空最后日期的数据统计
			$this->del('at_user_date', ' and ud_date = '.$date);
			$this->del('at_user_brand_date', ' and ubd_date = '.$date);
			$this->del('at_user_part_date', ' and upd_date = '.$date);

			//用户统计 at_user_date
			$filed = [
				'ud_date'=>'tj_date',
				'ud_uid'=>'tj_uid', 
				'ud_pv'=>'count(*)', 
				'ud_pjl_pv'=>"sum(case when tj_site = 'pjl' then 1 else 0 end)",
				'ud_yp_pv'=>"sum(case when tj_site = 'yp' then 1 else 0 end)",
				'ud_vin_pv'=>"sum(json_contains_path(tj_param, 'one', '$.vin'))",
				'ud_vin_count'=>"count(json_unquote(tj_param->'$.vin'))", 
				'ud_number_pv'=>"sum(json_contains_path(tj_param, 'one', '$.number'))",
				'ud_number_count'=>"count(json_unquote(tj_param->'$.number'))", 
				'ud_epc_pv'=>"sum(case when tj_act = 'data/epcModelPartItem' then 1 else 0 end)",
				'ud_epc_count'=>"count(CASE WHEN tj_act = 'data/epcModelPartItem' THEN CONCAT(JSON_UNQUOTE(tj_param->'$.grp2Id'), '@', JSON_UNQUOTE(tj_param->'$.mod3Id')) END)"
			];
			$sql = sprintf("insert into at_user_date(%s) select %s from at_tongji where tj_date = %d group by tj_date, tj_uid", implode(',', array_keys($filed)), implode(',', array_values($filed)), $date);
			$this->exeAnySql([$sql]);
			
			//用户关注的品牌
			if($date >= 20230712){
				//新算法
				$filed = [
					'ubd_date'=>'tj_date',
					'ubd_uid'=>'tj_uid', 
					'ubd_brand'=>"JSON_UNQUOTE(tj_param->'$.brand_name') brand", 
					'ubd_modtype'=>"JSON_UNQUOTE(tj_param->'$.modtype') modtype",
					'ubd_count'=>"count(*)",
				];
				$sql = sprintf("insert into at_user_brand_date(%s) select %s from at_tongji 
				where tj_date = %d and JSON_UNQUOTE(tj_param->'$.brand_name') !='' AND JSON_UNQUOTE(tj_param->'$.modtype') IN ('pc', 'cv') group by tj_date, tj_uid, upper(brand), modtype", implode(',', array_keys($filed)), implode(',', array_values($filed)), $date);
				$this->exeAnySql([$sql]);
			}else{
				//旧算法
				$where = sprintf(" and tj_date=%d AND LENGTH(JSON_UNQUOTE(tj_param->'$.vin'))=17 group by tj_uid, tj_vin order by tj_uid", $date);
				$vRes = $this->get('at_tongji', ["tj_uid, JSON_UNQUOTE(tj_param->'$.vin') AS tj_vin"], $where);
				$vinArr = [];
				$vinBrand = [];
				foreach($vRes['data'] as $vv)
				{
					$vv['tj_vin'] = LibFc::FormatVin($vv['tj_vin']);
					$bkey = substr($vv['tj_vin'], 0, 8).substr($vv['tj_vin'], 9, 3);
					$vinArr[$vv['tj_uid']][$bkey]++;
					$vinBrand[$bkey] = $bkey;
				}
				$vinBrand = array_values($vinBrand);

				//批量取对应关系
				$temp = [];
				$vinToBrand = [];
				$anyAddArr = [];
				foreach($vinBrand as $i=>$bkey)
				{
					$temp[] = $bkey;
					if(count($temp) == 1000 || ($i+1) == count($vinBrand))
					{
						$res = $YpwBase->Get('ypc_vin_brand_demo', ['concat(vbd_vin1_8, vbd_vin10_12) as bkey', 'vbd_brand', 'vbd_brand_id'], sprintf(" and concat(vbd_vin1_8, vbd_vin10_12) in ('%s') and vbd_brand != ''", implode("','", $temp)));
						foreach($res['data'] as $bv)
						{
							$vinToBrand[$bv['bkey']] = $bv;
						}
						$temp = [];
					}
				}
				
				foreach($vinArr as $uid=>$vs)
				{
					$brandCountArr = [];
					foreach($vs as $bkey=>$bcount)
					{
						if(isset($vinToBrand[$bkey]))
						{
							$trimKey = strtoupper(preg_replace("/(^\s+)|(\s+$)/u", '', $vinToBrand[$bkey]['vbd_brand']));
							$brandCountArr[$trimKey] += $bcount;
						}
					}
					foreach($brandCountArr as $bv=>$bc)
					{
						$anyAddArr[] = [
							'ubd_date'=>$date,	
							'ubd_uid'=>$uid,	
							'ubd_brand'=>$bv,	
							'ubd_count'=>$bc	
						];
						if(count($anyAddArr) == 1000)
						{
							
							$this->addAny('at_user_brand_date', array_keys($anyAddArr[0]), $anyAddArr);
							$anyAddArr = [];
						}
					}
				}
				if(!empty($anyAddArr))
					$this->addAny('at_user_brand_date', array_keys($anyAddArr[0]), $anyAddArr);
			}


			$anyAddArr = [];
			//用户关注的分类
			$where = sprintf(" and tj_date=%d AND JSON_CONTAINS_PATH(tj_param, 'one', '$.type') = 1 AND JSON_CONTAINS_PATH(tj_param, 'one', '$.proId') = 1 GROUP BY tj_uid, pro_type, pro_id, etk_id", $date);
			$pRes = $this->get('at_tongji', ["tj_uid, JSON_UNQUOTE(tj_param->'$.type') AS pro_type, JSON_UNQUOTE(tj_param->'$.proId') AS pro_id, JSON_UNQUOTE(tj_param->'$.etkId') AS etk_id"], $where);
			$userProArr = [];
			$proArr = [];
			foreach($pRes['data'] as $pv)
			{
				$pv['pro_type'] = in_array($pv['pro_type'], ['pjd', 'super'])? 'pjd': $pv['pro_type'];
				$pv['etk_id'] = (int) $pv['etk_id'];
				if($pv['pro_type'] == 'etk') $pv['pro_type'] = $pv['pro_type'].'@'.$pv['etk_id'];

				$pv['pro_id'] = (int) $pv['pro_id'];
				$proArr[$pv['pro_type']][] = $pv['pro_id'];
				$userProArr[$pv['tj_uid']][$pv['pro_type'].'_'.$pv['pro_id']]++;
			}
		
			//产品对应的分类
			$YpsBase = new YpsBase();
			$TcdmArt = new TcdmArt();
			$B2cBase = new B2cBase();
			$AaiaBase = new AaiaBase();
			$proPartArr = [];
			foreach($proArr as $ptype=>$tproIds)
			{
				$tproIds = array_unique($tproIds);
				$proIds = [];
				foreach($tproIds as $tk=>$tv)
				{
					$proIds[] = $tv;
					if(count($proIds) < 900  && ($tk+1) != count($tproIds)) continue;
					switch($ptype)
					{
						case 'yp':
							$table = 'yp_product AS p 
							JOIN yp_part AS pa ON p.partid = pa.partid
							JOIN yp_lng_des AS ld ON ld.desid = pa.desid AND ld.lngid = 1
							JOIN yp_lng_text AS lt ON lt.txtid = ld.txtid';
							$res = $YpsBase->get($table, ['p.pid AS pro_id, lt.txt AS part_name'], sprintf(" and p.pid in (%s)", implode(',', $proIds)));
							foreach($res['data'] as $pv)
							{
								$proPartArr[$ptype.'_'.$pv['pro_id']] = $pv['part_name'];
							}
						break;
						case 'tcd':
							$res = $TcdmArt->get('tof_articles join tof_generic_articles on ga_id=art_ga_id', ['art_id, ga_id, ga_name_cn'], sprintf(" and art_id in (%s)", implode(',', $proIds)));
							if(!empty($res['data']))
							{
								$gaIdArr = [];
								foreach($res['data'] as $pv)
								{
									$gaIdArr[$pv['ga_id']] = $pv['ga_name_cn'];
									$proPartArr[$ptype][$pv['art_id']] = $pv['ga_id'];
								}
								//优先找和宜配的对应关系
								$table = 'yp_part_tcdga AS pt JOIN yp_part AS pa ON pa.partid = pt.partid
								JOIN yp_lng_des AS ld ON ld.desid = pa.desid AND ld.lngid = 1
								JOIN yp_lng_text AS lt ON lt.txtid = ld.txtid';
								$res = $YpsBase->get($table, ['pt.ga_id, lt.txt AS part_name'], sprintf(" and pt.ga_id in (%s) group by pt.ga_id", implode(',', array_keys($gaIdArr))));
								foreach($res['data'] as $pv)
								{
									$gaIdArr[$pv['ga_id']] = $pv['part_name'];
								}

								foreach($proPartArr[$ptype] as $proId =>$gaId)
								{
									$proPartArr[$ptype.'_'.$proId] = $gaIdArr[$gaId];
								}
							}
						break;
						case 'pjd':
						case 'super':
							$res = $B2cBase->get('bc_product JOIN bc_part ON pro_part_id = part_id', ['pro_id, part_name'], sprintf(" and pro_id in (%s) AND part_name != ''", implode(',', $proIds)));
							foreach($res['data'] as $pv)
							{
								$proPartArr[$ptype.'_'.$pv['pro_id']] = $pv['part_name'];
							}
						break;
						case 'aaia':
							$table = 'yp_product AS p 
							JOIN yp_part AS pa ON p.partid = pa.partid
							JOIN yp_lng_des AS ld ON ld.desid = pa.desid AND ld.lngid = 1
							JOIN yp_lng_text AS lt ON lt.txtid = ld.txtid';
							$res = $YpsBase->get($table, ['p.pid AS pro_id, lt.txt AS part_name'], sprintf(" and p.pid in (%s)", implode(',', $proIds)));
							foreach($res['data'] as $pv)
							{
								$proPartArr[$ptype.'_'.$pv['pro_id']] = $pv['part_name'];
							}
						break;
						default:
							if(stripos($ptype, 'etk') === 0)
							{
								$etkId = substr($ptype, 4);
								if(!empty(mvc::$cfg['DB']['EPC'][$etkId]))
								{
									$EpcItem = new EpcItem($etkId);
									$res = $EpcItem->getAnyItemBase($proIds);
									foreach($res['data'] as $pv)
									{
										$proPartArr[$ptype.'_'.$pv['pro_id']] = $pv['grp2_name'];
									}
								}
							}

						break;
					}
					$proIds = [];
				}
			}
			
			foreach($userProArr as $uid=>$vs)
			{
				$partCountArr = [];
				$formatPart = [];
				foreach($vs as $bkey=>$bcount)
				{
					if(isset($proPartArr[$bkey]))
					{
						$trimKey = LibFc::msubstr($proPartArr[$bkey], 0, 30, 'utf-8', false);
						$trimKey = preg_replace("/(^\s+)|(\s+$)/u", '', $trimKey);
						$formatKey = strtoupper(LibFc::formatStr($trimKey, 1));
						$partCountArr[$formatKey] += $bcount;
						$formatPart[$formatKey] = $trimKey;
					}
				}
				foreach($partCountArr as $bv=>$bc)
				{
					$anyAddArr[] = [
						'upd_date'=>$date,
						'upd_uid'=>$uid,
						'upd_part'=>$formatPart[$bv],
						'upd_count'=>$bc	
					];

					if(count($anyAddArr) == 1000)
					{
						$this->addAny('at_user_part_date', array_keys($anyAddArr[0]), $anyAddArr);
						$anyAddArr = [];
					}
				}
			}
			if(!empty($anyAddArr)) $this->addAny('at_user_part_date', array_keys($anyAddArr[0]), $anyAddArr);
			$this->TjDb->End();
		}
		
		//最近6个月 处理活跃用户到总表
		$bDate = date('Ymd', strtotime('-6 month'));
		$dateCount = floor((time() - strtotime($bDate))/3600/24);
		

		$YpwBase = new YpwBase();
		$PjlBase = new PjlBase();
		$B2cBase = new B2cBase();
		$CrmDb = new BaseDb(mvc::$cfg['DB']['CRM']);

		$res = $PjlBase->get('pl_shop', ['shop_id', 'shop_vip_etime'], '');
		$shopEndTime = array_column($res['data'], null, 'shop_id');
		
		$this->TjDb->Begin();

		$YpwBase->del('yp_user_act', ' ');
		$YpwBase->del('yp_user_act_brand', ' ');
		$YpwBase->del('yp_user_act_part', ' ');

		//跑街令、商城的用户ID全部纳入
		$mustArr = [];
		$res = $PjlBase->get('pl_shop', ['shop_pu_id'], '');
		$mustArr = array_column($res['data'], 'shop_pu_id');

		$res = $B2cBase->get('sh_shop', ['shop_uid'], '');
		$mustArr = array_merge($mustArr, array_column($res['data'], 'shop_uid'));

		
		$filed = ['ud_uid, sum(ud_pv) as pv, sum(ud_pjl_pv) as pjl_pv, sum(ud_yp_pv) as yp_pv, sum(ud_vin_count) as vin_count, sum(ud_number_count) as number_count, sum(ud_epc_count) as epc_count'];
		$where = sprintf(" and ud_uid > 0 AND ( ud_uid in (%s) or ud_pv >= 20) and ud_date >=%d group by ud_uid", implode(',', $mustArr), $bDate);
		$ures = $this->get('at_user_date', $filed, $where);
		$userArr = array_column($ures['data'], null, 'ud_uid');
		
		foreach($mustArr as $uid)
		{
			if(empty($userArr[$uid])) $userArr[$uid] = ['ud_uid'=>$uid];
		}

		$temp = [];
		$i = 0;
		foreach($userArr as $uid=>$uv)
		{
			$i++;
			$temp[$uid] = $uv;
			if(count($temp) === 1000 || count($userArr) == $i)
			{
				$res = $PjlBase->get('pl_shop LEFT JOIN pl_shop_addr ON sha_shop_id = shop_id and sha_main =1', ['shop_pu_id', 'shop_style', 'shop_status', 'shop_id', 'shop_name', 'sha_name', 'sha_tel', 'shop_license'], sprintf(" and shop_pu_id in (%s) group by shop_pu_id", implode(',', array_keys($temp))));
				foreach($res['data'] as $sv)
				{
					$temp[$sv['shop_pu_id']]['ua_pjl_shop_id'] = $sv['shop_id'];
					$temp[$sv['shop_pu_id']]['ua_pjl_shop_status'] = $sv['shop_status'] == 2? 1: 0;
					$temp[$sv['shop_pu_id']]['ua_com_name'] = $sv['shop_name'];
					$temp[$sv['shop_pu_id']]['ua_com_style'] = $sv['shop_style'];

					if(empty($temp[$sv['shop_pu_id']]['ua_link_name'])) $temp[$sv['shop_pu_id']]['ua_link_name'] = $sv['sha_name'];
					if(empty($temp[$sv['shop_pu_id']]['ua_link_name']))
					{
						$t = json_decode($sv['shop_license'], true);
						$temp[$sv['shop_pu_id']]['ua_link_name'] = $t['realname'];
					}
					if(empty($temp[$sv['shop_pu_id']]['ua_link_tel'])) $temp[$sv['shop_pu_id']]['ua_link_tel'] = $sv['sha_tel'];
				}

				$res = $PjlBase->get('pl_user', ['pu_uid', 'pu_work_style'], sprintf(" and pu_uid in (%s)", implode(',', array_keys($temp))));
				foreach($res['data'] as $sv)
				{
					if(!empty($temp[$sv['shop_pu_id']]['ua_com_style']))
						$temp[$sv['shop_pu_id']]['ua_com_style'] = $sv['pu_work_style'];
				}

				$res = $B2cBase->get('sh_shop', ['shop_uid', 'shop_status', 'shop_id', 'shop_name', 'shop_main_tel', 'shop_main_name'], sprintf(" and shop_uid in (%s)", implode(',', array_keys($temp))));
				foreach($res['data'] as $sv)
				{
					$temp[$sv['shop_uid']]['ua_pjd_shop_id'] = $sv['shop_id'];
					$temp[$sv['shop_uid']]['ua_pjd_shop_status'] = $sv['shop_status'] == 1? 1: 0;
					if(empty($temp[$sv['shop_uid']]['ua_com_name'])) $temp[$sv['shop_uid']]['ua_com_name'] = $sv['shop_name'];

					if(empty($temp[$sv['shop_uid']]['ua_link_name'])) $temp[$sv['shop_uid']]['ua_link_name'] = $sv['shop_main_name'];
					if(empty($temp[$sv['shop_uid']]['ua_link_tel'])) $temp[$sv['shop_uid']]['ua_link_tel'] = $sv['shop_main_tel'];
				}

				$res = $YpwBase->get('yp_user left join yp_user_ext on ui_uid=u_id', ['u_id', 'u_mobile', 'u_email', 'u_real_name', 'ui_ctr_id'], sprintf(' and u_id in (%s)', implode(',', array_keys($temp))));
				
				$moArr = [];
				$ctrIds = [];
				foreach($res['data'] as $sv)
				{
					if(!empty($sv['u_mobile'])) $moArr[$sv['u_mobile']][] = $sv['u_id'];
					if(!empty($sv['u_email'])) $moArr[$sv['u_email']][] = $sv['u_id'];
					if(empty($temp[$sv['u_id']]['ua_link_name'])) $temp[$sv['u_id']]['ua_link_name'] = $sv['u_real_name'];
					if(empty($temp[$sv['u_id']]['ua_link_tel'])) $temp[$sv['u_id']]['ua_link_tel'] = $sv['u_mobile'];
					if(!empty($sv['ui_ctr_id'])){
						$ctrIds[] = $sv['ui_ctr_id'];
						$temp[$sv['u_id']]['ua_crm_ctr_id'] = $sv['ui_ctr_id'];
					}
				}

				$ctrValArr = [];
				if(!empty($moArr))
				{
					$res = $CrmDb->get('crm_info_contcat JOIN crm_contact ON ccc_id = data_id', ['ccc_ctr_id', 'value as val'], sprintf(" and value in ('%s')", implode("','", array_keys($moArr))));
					foreach($res['data'] as $sv)
					{
						$ctrIds[] =  $sv['ccc_ctr_id'];
						$ctrValArr[$sv['val']][] = $sv['ccc_ctr_id'];
					}
				}

				//获取crm客户的基本信息
				$ctrArr = [];
				if(!empty($ctrIds))
				{
					$ctrIds = array_unique($ctrIds);
					$table = sprintf("crm_customer LEFT JOIN crm_follow ON ctr_id = afw_ctr_id AND afw_id IN (
						SELECT MAX(afw_id) FROM crm_follow where afw_ctr_id in (%s) GROUP BY afw_ctr_id)", implode(',', $ctrIds));
					$res = $CrmDb->get($table, ['ctr_id, ctr_name_body, afw_usr, afw_modified, 0 as ua_crm_protect'], sprintf(" and ctr_id IN (%s) GROUP BY ctr_id ", implode(',', $ctrIds)));
					$ctrArr = array_column($res['data'], null, 'ctr_id');
					if(!empty($ctrArr))
					{
						//是否被保护
						$res = $CrmDb->get('crm_level_sort', ['cls_ctr_id'], sprintf(" and cls_ctr_id IN (%s) and cls_lvl_id in (3,4,5,6,7) GROUP BY cls_ctr_id", implode(',', array_keys($ctrArr))));
						foreach($res['data'] as $sv)
						{
							$ctrArr[$sv['cls_ctr_id']]['ua_crm_protect'] = 1;
						}
					}
				}
				
				foreach($moArr as $val=>$uids)
				{
					if(!empty($ctrValArr[$val]))
					{
						foreach($uids as $id)
						{
							$ctrId = $ctrValArr[$val][0];
							if(empty($temp[$id]['ua_crm_ctr_id']))
							{
								$temp[$id]['ua_crm_ctr_id'] = $ctrId;
							}
						}
					}
				}
				
				$addAny = [];
				foreach($temp as $tvv)
				{
					if(!empty($tvv['ua_crm_ctr_id']))
					{
						$ctrId = $tvv['ua_crm_ctr_id'];
						$tvv['ua_crm_user'] = $ctrArr[$ctrId]['afw_usr'];
						$tvv['ua_crm_last_time'] = (int) $ctrArr[$ctrId]['afw_modified'];
						$tvv['ua_crm_protect'] = (int) $ctrArr[$ctrId]['ua_crm_protect'];
						if(empty($tvv['ua_com_name'])) $tvv['ua_com_name'] = $ctrArr[$ctrId]['ctr_name_body'];
					}

					$addAny[] = [
						'ua_uid'=>$tvv['ud_uid'],
						'ua_pjl_shop_id'=>(int) $tvv['ua_pjl_shop_id'],
						'ua_pjl_shop_status'=>(int) $tvv['ua_pjl_shop_status'],
						'ua_pjl_shop_etime'=>(int) $shopEndTime[$tvv['ua_pjl_shop_id']]['shop_vip_etime'],
						'ua_pjd_shop_id'=>(int) $tvv['ua_pjd_shop_id'],
						'ua_pjd_shop_status'=>(int) $tvv['ua_pjd_shop_status'],
						'ua_com_name'=>$tvv['ua_com_name'],
						'ua_com_style'=>$tvv['ua_com_style'],
						'ua_link_name'=>$tvv['ua_link_name'],
						'ua_link_tel'=>$tvv['ua_link_tel'],
						'ua_pv'=>(int) $tvv['pv'],
						'ua_pjl_pv'=>(int) $tvv['pjl_pv'],
						'ua_yp_pv'=>(int) $tvv['yp_pv'],
						'ua_vin_count'=>(int) $tvv['vin_count'],
						'ua_number_count'=>(int) $tvv['number_count'],
						'ua_epc_count'=>(int) $tvv['epc_count'],
						'ua_crm_ctr_id'=>(int) $tvv['ua_crm_ctr_id'],
						'ua_crm_protect'=>(int) $tvv['ua_crm_protect'],
						'ua_crm_user'=>$tvv['ua_crm_user'],
						'ua_crm_last_time'=>(int)$tvv['ua_crm_last_time'],
					];
				}
				$YpwBase->addAny('yp_user_act', array_keys($addAny[0]), $addAny);
				$temp = [];
			}
		}
		
		$addAny = [];
		$res = $this->get('at_user_brand_date', ['ubd_uid', 'ubd_brand', 'ubd_modtype', 'sum(ubd_count) as ubd_count'], sprintf(" and ubd_uid > 0 and ubd_date >=%d group by ubd_uid, ubd_brand, ubd_modtype HAVING ubd_count >= 10", $bDate));
		foreach($res['data'] as $sk=>$sv)
		{
			$addAny[] = [
				'uab_uid'=>$sv['ubd_uid'],	
				'uab_brand'=>$sv['ubd_brand'],	
				'uab_modtype'=>$sv['ubd_modtype'],
				'uab_count'=>$sv['ubd_count'],
			];
			if(count($addAny) == 1000 || ($sk+1) == count($res['data']))
			{
				$YpwBase->addAny('yp_user_act_brand', array_keys($addAny[0]), $addAny);
				$addAny = [];
			}
		}

		$addAny = [];
		$res = $this->get('at_user_part_date', ['upd_uid', 'upd_part', 'sum(upd_count) as upd_count'], sprintf(" and upd_uid > 0 and upd_date >=%d group by upd_uid, upd_part HAVING upd_count >= 10", $bDate));
		foreach($res['data'] as $sk=>$sv)
		{
			$addAny[] = [
				'uap_uid'=>$sv['upd_uid'],	
				'uap_part'=>$sv['upd_part'],	
				'uap_count'=>$sv['upd_count']
			];
			if(count($addAny) == 1000 || ($sk+1) == count($res['data']))
			{
				$YpwBase->addAny('yp_user_act_part', array_keys($addAny[0]), $addAny);
				$addAny = [];
			}
		}

		//平均每天访问次数划分等级
		$scoreArr = [
			'5'=>['min'=>10],	
			'4.5'=>['min'=>3, 'max'=>10],	
			'4'=>['min'=>1, 'max'=>3],
			'3.5'=>['min'=>0.6, 'max'=>1],	
			'3'=>['min'=>0.28, 'max'=>0.6],	
			'2.5'=>['min'=>0.23, 'max'=>0.28],	
			'2'=>['min'=>0.18, 'max'=>0.23],	
			'1.5'=>['min'=>0.13, 'max'=>0.18],	
			'1'=>['min'=>0.1, 'max'=>0.13],	
			'0.5'=>['max'=>0.1]
		];
		foreach($scoreArr as $score=>$be)
		{
			$where = '';
			if(!empty($be['min'])) $where.= sprintf(" and round(ua_pv/%d, 2) >= %f", $dateCount, $be['min']);
			if(!empty($be['max'])) $where.= sprintf(" and round(ua_pv/%d, 2) < %f", $dateCount, $be['max']);
			$YpwBase->set('yp_user_act', ['ua_score'=>sprintf('%.1f', $score)], $where);
		}


		//品牌、分类的月报表
		$bmonth = '201901';
		$res = $this->get('at_part_month', ['max(bp_month) as bmonth'], '', true);
		if(empty($res['data']['bmonth'])) 
			$res = $this->get('at_user_part_date', ['min(left(upd_date, 6)) as bmonth'], '', true);
		if(!empty($res['data']['bmonth'])) $bmonth = $res['data']['bmonth'];
		$this->del('at_part_month', sprintf(" and bp_month>=%d", $bmonth));
		$sql = sprintf("insert into at_part_month(bp_month, bp_part, bp_count) select left(upd_date, 6),upd_part, sum(upd_count) from at_user_part_date where left(upd_date, 6) >= %d group by upd_part, left(upd_date, 6) HAVING SUM(upd_count) > 100", $bmonth);
		$this->exeAnySql([$sql]);

		$bmonth = '201901';
		$res = $this->get('at_brand_month', ['max(bm_month) as bmonth'], '', true);
		if(empty($res['data']['bmonth'])) 
			$res = $this->get('at_user_brand_date', ['min(left(ubd_date, 6)) as bmonth'], '', true);
		if(!empty($res['data']['bmonth'])) $bmonth = $res['data']['bmonth'];
		$this->del('at_brand_month', sprintf(" and bm_month>=%d", $bmonth));
		$sql = sprintf("insert into at_brand_month(bm_month, bm_brand, bm_modtype, bm_count) select left(ubd_date, 6),ubd_brand, ubd_modtype, sum(ubd_count) from at_user_brand_date where left(ubd_date, 6) >= %d group by ubd_brand, ubd_modtype, left(ubd_date, 6) HAVING SUM(ubd_count) > 100", $bmonth);
		$this->exeAnySql([$sql]);
		$this->TjDb->End();

		$this->TjDb->Begin();
		//将活跃用户导入到跑街CRM
		$sqlArr = [];
		$sqlArr[] = sprintf("INSERT INTO yp_crm.crm_customer (ctr_uid, ctr_score, ctr_comname, ctr_com_style, ctr_contact, ctr_tel, ctr_pjl_shop_id, ctr_pjl_shop_etime) 
		SELECT ua_uid, ua_score, ua_com_name, ua_com_style, ua_link_name, ua_link_tel, ua_pjl_shop_id, ua_pjl_shop_etime FROM ypdb_write.yp_user_act WHERE ua_uid NOT IN (SELECT ctr_uid FROM yp_crm.crm_customer)");
		//更新等级
		$sqlArr[] = 'UPDATE yp_crm.crm_customer, ypdb_write.yp_user_act SET ctr_score = ua_score WHERE ctr_uid = ua_uid AND ctr_score != ua_score';
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user_act SET ctr_comname = ua_com_name WHERE ctr_uid = ua_uid AND ctr_comname =''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user SET ctr_comname = u_nickname WHERE ctr_uid = u_id AND ctr_comname =''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user_act SET ctr_com_style = ua_com_style WHERE ctr_uid = ua_uid AND ctr_com_style =''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user_act SET ctr_contact = ua_link_name WHERE ctr_uid = ua_uid AND ctr_contact =''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user_act SET ctr_tel = ua_link_tel WHERE ctr_uid = ua_uid AND ctr_tel =''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user SET ctr_tel = u_mobile WHERE ctr_uid = u_id AND ctr_tel ='' and u_mobile !=''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, ypdb_write.yp_user_act SET ctr_pjl_shop_id = ua_pjl_shop_id WHERE ctr_uid = ua_uid AND ua_pjl_shop_id =0";
		//更新详细地址
		$sqlArr[] = "UPDATE yp_crm.crm_customer, yp_paojieling.pl_shop SET ctr_addr = shop_addr WHERE ctr_uid = shop_pu_id AND ctr_addr = '' and shop_addr!=''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, yp_paojieling.pl_repair SET ctr_addr = shopr_addr WHERE ctr_uid = shopr_pu_id AND ctr_addr = '' and shopr_addr != ''";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, yp_paojieling.pl_shop SET ctr_pjl_shop_applytime = shop_apply_time, ctr_pjl_shop_entertime = shop_enter_time WHERE ctr_uid = shop_pu_id";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, (SELECT uvl_uid, MAX(uvl_pay_time) uvl_pay_time FROM yp_paojieling.pl_user_vip_list WHERE uvl_status = 2 AND uvl_pay_time >0  GROUP BY uvl_uid) t SET ctr_pjl_shop_lastpaytime = uvl_pay_time WHERE ctr_uid = uvl_uid";
		$sqlArr[] = "UPDATE yp_crm.crm_customer, yp_paojieling.pl_shop SET ctr_pjl_shop_etime = shop_vip_etime WHERE ctr_uid = shop_id";
		$sqlArr[] = "UPDATE yp_crm.crm_customer SET ctr_pjl_shop_etime = 0 WHERE ctr_pjl_shop_etime IS NULL";
		$sqlArr[] = "UPDATE ypdb_write.yp_user_act_brand, ypb2c_common_a.bc_brand SET uab_brand_id = brand_id WHERE brand_name = uab_brand";
		$YpwBase->exeAnySql($sqlArr);
		
		//接口更新地区
		$OthPct = new OthPct();
		$ures = $YpwBase->get('yp_user', ['u_id, u_mobile'], " and u_pct_ids = '' AND u_mobile_check = 'Y' AND u_id IN (SELECT ua_uid FROM yp_user_act) AND u_status = 1");
		foreach($ures['data'] as $uv)
		{
			$res = $OthPct->getMobileInfo($uv['u_mobile']);
			if(!empty($res['data']['pctids']))
			{
				$pctIdArr = $res['data']['pctids'];
				$YpwBase->set('yp_user_ext', ['ui_province'=>(int) $pctIdArr[0], 'ui_city'=>(int) $pctIdArr[1]], ' and ui_province = 0 and ui_uid='.$uv['u_id']);
				$YpwBase->set('yp_user', ['u_pct_ids'=>implode(',', $pctIdArr)], ' and u_pct_ids="" and u_id='.$uv['u_id']);
			}
		}

		//更新地区
		$res = $YpwBase->get('yp_crm.crm_customer JOIN ypdb_write.yp_user ON u_id = ctr_uid', ['ctr_uid, u_pct_ids'], " and u_pct_ids != '' AND JSON_UNQUOTE(ctr_pct_ids->'$.pid') = 0");
		foreach($res['data'] as $v)
		{
			$t = explode(',', $v['u_pct_ids']);
			$setArr = [
				'ctr_pct_ids'=>json_encode( 
					[
					'pid'=>(int) $t[0],	
					'cid'=>(int) $t[1],	
					'tid'=>(int) $t[2]
					]
				)
			];
			$YpwBase->set('yp_crm.crm_customer', $setArr, sprintf(" and ctr_uid=%d", $v['ctr_uid']));
		}
		$this->TjDb->End();

		//防止事务有问题  CRM成交客户分配业务员， 最近7天
		/*$CrmMain = new CrmMain();
		$res = $PjlBase->get('dl_order_list', ['dml_dwo_uid, dml_order_uid'], sprintf(" and dml_atime > %d", $ctrArr['ctr_uid'], $now-3600*24*7));
		foreach($res['data'] as $v)
		{
			$CrmMain->changeCtrAutoStatus(0, $v['dml_dwo_uid'], $v['dml_order_uid']);
		}*/
		return LibFc::ReturnData(true);
    }
	
	//单一车架号查询 列入黑名单
	public function onlyDecodeVinBlack($bdate = '')
	{
		$YpwBase = new YpwBase();
		$OthB2cDb = new BaseDb(mvc::$cfg['DB']['B2COTH']);
		if(!$this->adsMinDate){
			$res = $OthB2cDb->get('pj_ads_show', ['min(as_date) min_date'], '', true);
			$this->adsMinDate = $res['data']['min_date'];
		}
		
		if(empty($bdate)) $bdate = date('Ymd');
		$act = 'data/decodeVin';
		$froms = ['PJLAND','PJLIOS'];
		$tjTables = ['at_tongji', 'at_tongji_all'];
		
		//有查车架号，但是无广告展示
		$minCount = 15;
		//防止数据延迟误算
		$res = $OthB2cDb->get('pj_ads_show', ['as_atime'], sprintf(" and as_atime >= %d limit 1", time()-3600), true);
		if($res['data'] && $bdate > $this->adsMinDate){
			$where = sprintf(" and tj_uid > 0 and tj_uid not in (select bl_uid from tj_blacklist where bl_type='user' and bl_etime > %d) AND tj_date='%d' AND tj_act='%s' and tj_from in ('%s') GROUP BY tj_uid HAVING COUNT(DISTINCT JSON_UNQUOTE(tj_param->'$.vin')) >= %d order by count(*) desc", time(), $bdate, $act, implode("','", $froms), $minCount);
			foreach($tjTables as $table){
				$ures = $this->get($table, ["tj_uid uid, COUNT(DISTINCT JSON_UNQUOTE(tj_param->'$.vin')) vin_count"], $where);
				if(!empty($ures['data'])) break;
			}
			$chunkArr = array_chunk($ures['data'], 500);
			foreach($chunkArr as $tjUArr){
				foreach($tjUArr as $kk=>$vv){
					if($this->hasAdsShowUids[$vv['uid']]){
						unset($tjUArr[$kk]);
					}
				}
				if(empty($tjUArr)) continue;
				$res = $OthB2cDb->get('pj_ads_show', ['distinct as_view_uid'], sprintf(" and as_view_uid in (%s) and as_date=%d group by as_view_uid", implode(',', array_column($tjUArr, 'uid')), $bdate));
				foreach($res['data'] as $tvv){
					$this->hasAdsShowUids[$tvv['as_view_uid']] = 1;
				}
				foreach($tjUArr as $uv){
					if(!isset($this->hasAdsShowUids[$uv['uid']])){
						$msg = '跑街令车架号:'.$uv['vin_count'].' 广告:0 ['.$bdate.']，禁止解封';
						$this->stopUser($uv['uid'], $msg);
					}
				}
			}
		}

		//最近7天
		$mindate = date('Ymd', strtotime('-7 day', strtotime($bdate)));
		if($bdate == date('Ymd') && $mindate > $this->adsMinDate){
			$minCount = 80;
			$where = sprintf(" and tj_uid > 0 and tj_uid not in (select bl_uid from tj_blacklist where bl_type='user' and bl_etime > %d) AND tj_date BETWEEN %d and %d AND tj_act='%s' and tj_from in ('%s') GROUP BY tj_uid HAVING COUNT(DISTINCT JSON_UNQUOTE(tj_param->'$.vin')) >= %d order by count(*) desc", time(), $mindate, $bdate, $act, implode("','", $froms), $minCount);
			foreach($tjTables as $table){
				$ures = $this->get($table, ["tj_uid uid, COUNT(DISTINCT JSON_UNQUOTE(tj_param->'$.vin')) vin_count"], $where);
				if(!empty($ures['data'])) break;
			}
			$chunkArr = array_chunk($ures['data'], 500);
			foreach($chunkArr as $tjUArr){
				foreach($tjUArr as $kk=>$vv){
					if($this->hasAdsShowUids[$vv['uid']]){
						unset($tjUArr[$kk]);
					}
				}
				if(empty($tjUArr)) continue;
				$res = $OthB2cDb->get('pj_ads_show', ['distinct as_view_uid'], sprintf(" and as_view_uid in (%s) and as_date BETWEEN %d and %d group by as_view_uid", implode(',', array_column($tjUArr, 'uid')), $mindate, $bdate));
				foreach($res['data'] as $tvv){
					$this->hasAdsShowUids[$tvv['as_view_uid']] = 1;
				}
				foreach($tjUArr as $uv){
					if(!isset($this->hasAdsShowUids[$uv['uid']])){
						$msg = '跑街令车架号:'.$uv['vin_count'].' 广告:0 ['.$bdate.']，禁止解封';
						$this->stopUser($uv['uid'], $msg);
					}
				}
			}
		}
		return LibFc::ReturnData(true);
	}
	
	//封账号
	function stopUser($uid, $msg)
	{
		$YpwBase = new YpwBase();
		$addArr = [
			'bl_type'=>'user',
			'bl_adate'=>date('Ymd'),
			'bl_uid'=>$uid,
			'bl_ip'=>'',
			'bl_atime'=>time(),
			'bl_etime'=>strtotime('+10 years'),
			'bl_remark'=>$msg
		];
		$this->add('tj_blacklist', $addArr);
		$YpwBase->Set('yp_user', ['u_status'=>'-2', 'u_status_remark'=>$msg], sprintf(" and u_id =%d and u_status = 1", $uid));
	}
}