<?php
/**
  * @method 零件分类管理
  * @author soul
  * @copyright 2016/3/31
  */
class B2cPart extends B2cBase
{
	
	/**
	  * @method 重置零件的字母
	  * @author soul
	  * @copyright 2017/6/5
	  * @return [["status"]=> bool(true) ["data"]=> ["code"]=> int(0) ]
	  */
	public function resetPartInitial()
	{
		$Res = $this->get('bc_part', ['part_id', 'part_name', 'part_initial']);
		$this->B2CDb->Begin();
		foreach($Res['data'] as $V)
		{
			$Initial = LibFc::GetInitial($V['part_name']);
			if($Initial != $V['part_initial'])
			{
				$this->set('bc_part', ['part_initial'=>$Initial], ' and part_id='.$V['part_id']);
			}
		}
		$this->B2CDb->End();
		return LibFc::ReturnData(true, true);
	}


	/**
	  * @method 获取所有零件
	  * @param  $cache  true|false   false:将重置缓存
	  * @author soul
	  * @copyright 2017/6/5
	  * @return [["status"]=> bool(true) ["data"]=> [1=>['part_id'=>1, 'part_name'=>''], ....] ["code"]=> int(0) ]
	  */
	public function getAllPart($cache = true)
	{
		$file = mvc::$cfg['AUTOLOAD']['B2c']['path'].'cache/allPart.php';
		$resArr = [];
		if(!file_exists($file) || !$cache)
		{
			$Res = $this->get('bc_part join bc_part_tree on part_id = pt_part_id and pt_ismain=1', ['bc_part.*'], ' order by pt_seq, part_initial');
			foreach($Res['data'] as $V)
			{
				$resArr[$V['part_id']] = $V;
			}
			LibFc::ArraySave($resArr, $file);
		}
		else
		{//括起来为了防止读取文件失败
			$resArr = include($file);
		}
		return LibFc::ReturnData(true, $resArr);
	}


	/**
	  * @method 零件名称供搜索关键字自动识别使用
	  * @param  $cache  true|false   false:将重置缓存
	  * @author soul
	  * @copyright 2017/6/5
	  * @return [["status"]=> bool(true) ["data"]=> 多维维数组 ["code"]=> int(0) ]
	  */
	public function getPartNameKeywordCache($Cache = true)
	{
		$file = mvc::$cfg['AUTOLOAD']['B2c']['path'].'cache/partNameKeyword.php';
		if(!file_exists($file) || !$Cache)
		{
			$res = $this->getAllPart();
			$outArr = [];
			
			foreach($res['data'] as $partid=>$v)
			{
				if($v['part_is_end'] ==1)
				{
					$tempArr = [];
					$v['part_name'] = strtoupper(trim($v['part_name']));
					$tempArr[] = $v['part_name'];
					if(preg_match("/[\x7f-\xff]/", $v['part_name'])) 
					{
						//中文拼音、首字母
						$tempArr[] = LibFc::PinYin($v['part_name']);
						$tempArr[] = LibFc::GetInitial($v['part_name']);
					}
					$tempArr = array_unique($tempArr);
					foreach($tempArr as $vv)
					{
						$wordArr = preg_split('/[\s,]/', strtoupper($vv));
						$wordArr[] = $partid;
						$outArr = array_merge_recursive($outArr, LibFc::arrToKeyArr($wordArr));
					}
				}
			}
			LibFc::ArraySave($outArr, $file);
		}
		else
		{//括起来为了防止读取文件失败
			$outArr = include($file);
		}
		return LibFc::ReturnData(true, $outArr);
	}


	/**
	  * @method 获取某分类的参数
	  * @param  $partid 配件分类ID
	  * @author soul
	  * @copyright 2017/6/5
	  * @return [["status"]=> bool(true) ["data"]=> [['pal_id'=>, 'pal_name'=>, 'pau_id'=>, 'pau_name'=>], .....]["code"]=> int(0) ]
	  */
	public function getPartParam($partid)
	{
		$partid = (int) $partid;
		$resArr = [];
		if($partid > 0)
		{
			$table = 'bc_part_param_link join bc_param_label on ppl_pal_id=pal_id left join bc_param_unit on ppl_pau_id = pau_id';
			$res = $this->get($table, ['pal_id', 'pal_name', 'pau_id', 'pau_name', 'ppl_style','ppl_seq'], sprintf(" and ppl_part_id = %d order by ppl_seq", $partid));
			$resArr = $res['data'];
		}
		return LibFc::ReturnData(true, $resArr);
	}
	/**
	  * @method 添加店铺最近使用的零件
	  * @param  $shopId 店铺ID
	  * @param  $partPath 路径 如0,2,3
	  * @author soul
	  * @copyright 2017/6/5
	  * @return [["status"]=> bool(true) ["data"]=> ["code"]=> int(0) ]
	  */
	public function addRecentPart($shopId, $partPath)
	{
		$shopId = (int) $shopId;
		if($shopId > 0 && $partPath != '')
		{
			$res = $this->get('bc_part_tree', ['count(*) count'], sprintf(" and concat(pt_path,',', pt_part_id) ='%s'", LibFc::Escape($partPath)), true);
			if(!empty($res['data']['count']))
			{
				$where = sprintf(" and rep_shop_id =%d and rep_part_path ='%s'", $shopId, LibFc::Escape($partPath));
				$res = $this->get('sh_recent_part', ['count(*) count'], $where, true);
				if(!empty($res['data']['count']))
				{
					$this->set('sh_recent_part', ['rep_etime'=>time()], $where);
				}
				else
				{
					$this->add('sh_recent_part', ['rep_shop_id'=>$shopId, 'rep_part_path'=>$partPath, 'rep_etime'=>time()]);
				}
			}
		}
		return LibFc::ReturnData(true, true);
	}
	/**
	 * @method    获取树型图零件列表
	 * @return    [array]      [array('status'=>true,'data'=>array('pt_part_id'=>1,'children'=>array('pt_part_id'=>2)))]
	 * @author 卢
	 * @copyright 2017-07-12
	 */
	public function getPartTree($tree,$path='0')
	{
		if(is_array($tree))
		{
			$data=array();
			foreach ($tree as $key => $value) 
			{
				if($value['pt_path']==$path)
				{
					if($value['part_is_end'] == 1){
						$res = ['data'=>[]];
					}else{
						$res=$this->getPartTree($tree,$value['pt_path'].','.$value['pt_part_id']);
						$value['state']='closed';
						foreach ($res['data'] as $i => $j) 
						{
							$value['productCount']+=$j['productCount'];
						}
					}
					$value['children']=$res['data'];
					$data[]=$value;
				}
			}
			return LibFc::ReturnData(true,$data);
		}
		return LibFc::ReturnData(false,'参数不正确');
	}
	/**
	 * @method    获取该ID下末级子类(未去重)
	 * @param     [array]       $tree [所有树数据]
	 * @param     [int]      $path [父级零件id]
	 * @return    [array]             [Array([0] => Array([part_id] => 730056,[pt_parent_part_id] => 610056,[part_is_end] => 1)[1] => Array([part_id] => 730056,pt_parent_part_id] => 610056,[part_is_end] => 1))]
	 * @author 卢
	 * @copyright 2017-07-25
	 */
	public function getPartIsEnd($tree,$part=0)
	{
		if(is_array($tree))
		{
			$data=[];
			// static $data=array();
			foreach ($tree as $k => $v) 
			{
				if($v['part_id']==$part&&$v['part_is_end']>0)
				{
					$data[]=$v;
					continue;
				}
				if($v['pt_parent_part_id']==$part)
				{
					if($v['part_is_end']>0)
					{
						$data[]=$v;
						continue;
					}
					$res=$this->getPartIsEnd($tree,$v['part_id']);
					$data=array_merge($data,$res['data']);
				}
			}
			return LibFc::ReturnData(true,$data);
		}
		return LibFc::ReturnData(false,'参数不正确');
	}
	/**
	 * @method    根据父ID获取子零件
	 * @param     [int]       $parentId [父ID]
	 * @return    [array]                 [array([0]=>{['part_id']=>1,['part_name']=>'点火系统'})]
	 * @author 卢
	 * @copyright 2017-07-12
	 */
	public function getPartByPid($parentId=0)
	{
		$data=array();
		$allPart=$this->getAllPart(false);
		$where=sprintf(' and pt_parent_part_id =%d',$parentId);
		$existsData=$this->getFieldUniVal('bc_part_tree','pt_part_id',$where);
		foreach ($existsData['data'] as $k => $v) 
		{
			$data[$v]=$allPart['data'][$v];
		}
		return LibFc::ReturnData(true,$data);
	}
	/**
	 * @method    根据条件获取零件
	 * @param     [array|string]              $field [array('part_id',.....)|'part_id']
	 * @param     [type]              $where [条件]
	 * @return    [type]                     [array('status'=>true,'data'=>array('part_id',.....))]
	 * @author 卢
	 * @copyright 2017-07-12
	 */
	public function getPartsByCondition($field,$where)
	{
		if(empty($where))
		{
			return LibFc::ReturnData(false,'参数错误');
		}
		$fields=empty($field)? ['*'] : $field;
		$table='bc_part left join bc_part_tree on part_id=pt_part_id';
		$data=$this->Get($table,$fields,$where);
		return $data;
	}
	/**
	 * @method    添加零件基本信息
	 * @param     [array]     $baseArr     
	 * @param     [array]     $ParentArr [array('0'=>123,'1'=>456)]
	 * @author 卢
	 * @copyright 2017-07-14
	 * @return   [array('status'=>true,'data'=>123)] [添加成功的零件ID]	
	 */
	public function AddPart($baseArr, $ParentArr)
	{
		if(count($ParentArr) > 0&&count($baseArr) && !empty($baseArr['part_name']))
		{
			$IsMain = $baseArr['IsMain'];
			unset($baseArr['IsMain']);

			//零件名是否重复
			$baseArr['part_is_end'] = ($baseArr['part_is_end']==1) ? 1:0;
			$res = $this->get('bc_part',['part_id'],sprintf(" and part_is_end=%d and part_name='%s'", $baseArr['part_is_end'], LibFc::Escape($baseArr['part_name'])),true);
			if(!empty($res['data'])) return LibFc::ReturnData(false, '零件已经存在!');
			
			$baseArr['part_initial'] = LibFc::GetInitial($baseArr['part_name']);

			if(isset($baseArr['part_sup_names']))
			{
				$baseArr['part_sup_names'] = array_unique(explode(',', $baseArr['part_sup_names']));
				sort($baseArr['part_sup_names']);
				$res = $this->getSupIdsByNames($baseArr['part_sup_names']);
				$baseArr['part_sup_names'] = implode(',', $baseArr['part_sup_names']);
				$baseArr['part_sup_ids_tcdcn'] = implode(',', $res['data']['tcdcn']);
			}

			if(isset($baseArr['part_opart_names']))
			{
				$baseArr['part_opart_names'] = array_unique(explode(',', $baseArr['part_opart_names']));
				sort($baseArr['part_opart_names']);
				$res = $this->getPartIdsByNames($baseArr['part_opart_names']);
				$baseArr['part_opart_names'] = implode(',', $baseArr['part_opart_names']);
				$baseArr['part_opart_ids_tcdcn'] = implode(',', $res['data']['tcdcn']);
			}

			$this->B2CDb->Begin();
			$res = $this->Add('bc_part',$baseArr);
			$partId = $res['data'];
			$baseArr['part_id'] = $partId;

			$this->AddPartTree($partId, $ParentArr, $IsMain);
			$this->B2CDb->End();
			// 返回
			return LibFc::ReturnData(true, $partId);
		}
		return LibFc::ReturnData(false, '添加的零件分类参数不正确。');
	}



	
	/**
	 * @method    添加零件父类
	 * @param     [int]      $PartId     [零件ID]
	 * @param     [array]      $ParentArr  [父类ID数组array('0'=>123,'1'=>456)]
	 * @param     [int]      $MainParent [主父类]
	 * @author 卢
	 * @return   [bool]
	 * @copyright 2017-07-14
	 */
	public function AddPartTree($PartId, $ParentArr, $MainParent)
	{
		$PartId = LibFc::Int($PartId);
		$ParentArr = is_array($ParentArr) ? $ParentArr: array(0);
		if($PartId > 0 && count($ParentArr) > 0)
		{
			$this->B2CDb->Begin();
			foreach($ParentArr as $ParentId)
			{
				// echo '<hr>';
				$IsMainVal = $ParentId == $MainParent? 1 : 0;
				if($ParentId == 0)
				{
					$Level = 1;
					$Path=0;
					$targetArr=array('pt_part_id'=>$PartId,'pt_parent_part_id'=>$ParentId,'pt_level'=>$Level,'pt_path'=>$Path,'pt_ismain'=>$IsMainVal);
					$ResFlag = $this->Add('bc_part_tree',$targetArr);
					if(!$ResFlag['status'])
					{
						return LibFc::ReturnData(false, '新增该零件的父级SQL语句执行失败。');
					}
				}
				else
				{
					$Res=$this->Get('bc_part_tree',['*'], 'and pt_part_id='.$ParentId);
					if(!$Res['status'])
					{
						return LibFc::ReturnData(false, $Res['data']);
					}
					foreach ($Res['data'] as $key => $value) 
					{
						$Level = $Res['data'][$key]['pt_level']+1;
						$Path = $Res['data'][$key]['pt_path'].','.$ParentId;
						$targetArr=array('pt_part_id'=>$PartId,'pt_parent_part_id'=>$ParentId,'pt_level'=>$Level,'pt_path'=>$Path,'pt_ismain'=>$IsMainVal);
						$ResFlag = $this->Add('bc_part_tree',$targetArr);
						if(!$ResFlag['status'])
						{
							return LibFc::ReturnData(false, '新增该零件的父级SQL语句执行失败。');
						}
					}
				}
				
			}
			$this->B2CDb->End();
			return LibFc::ReturnData(true,true);
		}
		return LibFc::ReturnData(false, '提供的参数不正确。');
	}
	/**
	 * @method    添加/修改零件参数
	 * @param     [array]  
	 * @return   [bool]
	 * @author 卢
	 * @copyright 2017-07-14
	 */
	public function setPartPara($partId, $paraArr)
	{
		$res = $this->get('bc_part', ['*'], sprintf(" and part_id=%d", $partId), true);
		if(empty($res['data'])) return LibFc::ReturnData(false, '零件分类不存在！');
		$partArr = $res['data'];
		
		$res = $this->get('bc_part_param_link', ['*'], sprintf(" and ppl_part_id=%d", $partArr['part_id']));
		$hasArr = array_column($res['data'], 'ppl_pal_id');

		$this->B2CDb->Begin();
		if(empty($partArr['part_is_end']))
		{
			$delArr = $hasArr;
		}
		else
		{
			$delArr = array_diff($hasArr, array_keys($paraArr));
			$seq = 0;
			foreach($paraArr as $id=>$v)
			{
				$seq++;
				if(!empty($v['pal_name']))
				{
					$v['ppl_part_id'] = $partId;
					$v['ppl_seq'] = $v['ppl_seq'] == '' ? $seq: (int) $v['ppl_seq'];
					if(isset($v['ppl_pau_id'])) $v['ppl_pau_id'] = (int) $v['ppl_pau_id'];
					if(isset($v['ppl_style'])) $v['ppl_style'] = (int) $v['ppl_style'];
					
					foreach($v as $filed=>$fv)
					{
						if(stripos($filed, 'ppl_toname_') !== false)
						{
							$ret = [';'=>',', ';'=>',', '，'=>','];
							$t = [];
							foreach(explode(',', strtr($fv, $ret)) as $tv) 
							{
								$tv = trim($tv);
								if($tv != '')
								{
									$t[] = $tv;
								}
							}
							$v[$filed] = implode(',', $t);
						}
					}

					if($id > 0)
					{
						$this->set('bc_param_label',['pal_name'=>$v['pal_name']],sprintf(' and pal_id=%d', $id));
						unset($v['pal_name']);
						$this->set('bc_part_param_link', $v, sprintf(" and ppl_pal_id=%d and ppl_part_id=%d", $id, $partArr['part_id']));
					}
					else
					{
						$v['ppl_part_id'] = $partArr['part_id'];
						$res = $this->add('bc_param_label',['pal_name'=>$v['pal_name']]);
						$v['ppl_pal_id'] = $res['data'];
						unset($v['pal_name']);
						$this->add('bc_part_param_link', $v);
					}
				}
			}
		}
		if(!empty($delArr))
		{
			$this->del('bc_param_label', sprintf(" and pal_id in (%s)", implode(',', $delArr)));
			$this->del('bc_part_param_link', sprintf(" and ppl_part_id=%d and ppl_pal_id in (%s)", $partArr['part_id'], implode(',', $delArr)));
			$this->del('bc_param_value', sprintf(" and pav_part_id=%d and pav_pal_id in (%s)", $partArr['part_id'], implode(',', $delArr)));
			//参数值
			$this->del('bc_product_param_string', sprintf(" and pps_pal_id in (%s)", implode(',', $delArr)));
			$this->del('bc_product_param_float', sprintf(" and ppf_pal_id in (%s)", implode(',', $delArr)));
		}
		$this->B2CDb->End();
		return LibFc::ReturnData(true);
	}
	/**
	 * @method    根据参数ID获取产品数量
	 * @param     [int]               $Style   [参数类型]
	 * @param     [int]               $LabelId [参数ID]
	 * @author 卢
	 * @return   [int] [该参数下的产品数量]
	 * @copyright 2017-07-14
	 */
	public function GetProCountByLabelId($Style, $LabelId)
	{
		$LabelId = LibFc::Int($LabelId);
		if( $LabelId > 0)
		{
			$Style = $Style == 0? 'string': 'float';
			$type=$Style == 'string'? 'pps': 'ppf';
			$field=$Style == 'string'? 'pps_pal_id': 'ppf_pal_id';
			$table=sprintf('bc_product left join bc_product_param_%s on %s_pro_id=pro_id',$Style,$type);
			$where=sprintf(' and %s_pal_id=%d',$type,$LabelId);
			$Res =$this->Get($table,['distinct '.$field],$where);
			if($Res['status'])
			{
				return LibFc::ReturnData(true, count($Res['data']));
			}
			return LibFc::ReturnData(false, '查询SQL语句失败。');
		}
		return LibFc::ReturnData(false, '提供的参数不正确。');
	}
	/**
	 * @method    根据参数值ID获取产品数量
	 * @param     [int|arr]             $valId [参数值ID]
	 * @author 卢
	 * @return   [arr]  ['status'=>true,'data'=>['值ID'=>'配件数量']]
	 * @copyright 2018-02-27
	 */
	public function GetProCountByValLabelId($valId)
	{
		$valArr = is_array($valId)?$valId:[(int)$valId];
		if( count($valArr) > 0)
		{
			$res=$this->get('bc_product_param_float',['count(*) count','ppf_pav_id'],sprintf(' and ppf_pav_id in (%s) group by ppf_pav_id',implode(',',$valArr)));
			return $res;
		}
		return LibFc::ReturnData(false, '提供的参数不正确。');
	}
	/**
	 * @method    删除零件
	 * @param     [int]     $partId [要删除的零件ID]
	 * @return    [bool]  
	 * @author 卢
	 * @copyright 2017-07-14
	 */
	public  function delPart($partId)
	{
		$partId = (int) $partId;
		if($partId < 1) return LibFc::ReturnData(true);
		$res = $this->getPartByPid($partId);
		if(count($res['data']) > 0) return LibFc::ReturnData(false, '该零件下有'.count($res['data']).'个子分类，请先删除子类！');
		
		$res = $this->get('bc_product',['count(*) as count'],sprintf(' and pro_part_id=%d',$partId), true);
		if($res['data']['count'] > 0) return LibFc::ReturnData(false, '有'.$res['data']['count'].'个产品正在使用该分类，禁止删除！');
		
		$this->B2CDb->Begin();
		//删除配件参数值
		$this->del('bc_product_param_float',sprintf(' and ppf_pro_id in(select pro_id from bc_product where pro_part_id = %d)', $partId));
		$this->del('bc_product_param_string',sprintf(' and pps_pro_id in(select pro_id from bc_product where pro_part_id = %d)', $partId));

		//删除参数值
		$this->del('bc_param_value',sprintf(' and pav_part_id = %d',  $partId));
		//删除参数名
		$this->del('bc_param_label',sprintf(' and pal_id in(select ppl_pal_id from bc_part_param_link where ppl_part_id = %d)', $partId));
		//删除分类与参数对应关系表
		$this->del('bc_part_param_link',sprintf(' and ppl_part_id = %d', $partId));

		//删除分类树
		$this->del('bc_part_tree',sprintf(' and pt_part_id = %d', $partId));
		//删除分类
		$this->del('bc_part',sprintf(' and part_id = %d', $partId));
		$this->B2CDb->End();
		return LibFc::ReturnData(true, true);
	}
	/**
	 * @method    校验零件唯一性
	 * @param     array      $partName [零件名]
	 * @param     int    $PartId   [零件ID默认为0]
	 * @return    [array]               [返回改零件名已有的数量 array('status'=>true,'data'=>array('count'=>1))]
	 * @author 卢
	 * @copyright 2017-07-17
	 */
    public function checkPart($partName = array(), $PartId = 0) 
    {
        $PartId = LibFc::Int($PartId);
        if(empty($partName) || !is_array($partName)){
            return LibFc::ReturnData(false, '提供的partName格式不正确。');
        }
        //组成WHERE条件
        $Where = '';
        foreach($partName as $K=>$V) {
            $K = LibFc::Escape($K);
            $V = LibFc::Escape($V);
            if($V == '' || $K == '') {
                return LibFc::ReturnData(false, '提供的partName不正确。');
            }
            $Where .= sprintf("and %s = '%s' ",$K,$V);
        }
        if($PartId > 0) {
            $Where .= sprintf(" and part_id != %d",$PartId);
        }
		$Res = $this->Get('bc_part',['count(*) count'],$Where,true);
		return $Res;
    }
    /**
     * @method    根据零件ID计算产品数量
     * @param     [int]      $PartId [零件ID]
     * @param     [array]    $tree [所有零件]
     * @return    [array]              [返回改零件的产品数量 array('status'=>true,'data'=>array('count'=>1))]
     * @author 卢
     * @copyright 2017-07-18
     */
    public function getProCount($PartId)
    {
    	if(LibFc::Int($PartId))
    	{
    		$where=sprintf(' and pro_part_id=%d',$PartId);
    		$Res =$this->Get('bc_product',['count(*) count'],$where,true);
    		return $Res;
    	}
    	return LibFc::ReturnData(false, '参数不正确。');
    }
    /**
     * @method    修改零件树
     * @param     [int]      $PartId     [零件ID]
     * @param     [array]      $ParentArr  [零件父类数组 array([Parent] => Array([0] => 410056 [1] => 116))]
     * @param     [int]      $IsEnd      [是否为末级]
     * @param     [int]      $MainParent [主父类ID]
     * @return   [array] [array('status'=>true,'data'=>true)]
     * @author 卢
     * @copyright 2017-07-18
     */
    public function setPartTree($PartId, $ParentArr, $IsEnd, $MainParent)
	{
		$PartId = LibFc::Int($PartId);
		$ParentArr = is_array($ParentArr) ? $ParentArr: array(0);
		$IsEnd = $IsEnd > 0? 1: 0;
		if($PartId > 0 && count($ParentArr) > 0 && in_array($MainParent, $ParentArr))
		{		
			//获取旧的亲父亲和是否为最后一级
			$Res = $this->getPartsByCondition(['*'],' and pt_ismain=1 and pt_part_id='.$PartId);
			if(!$Res['status'])
			{
				return LibFc::ReturnData(false, $Res['data']);
			}
			$OldPartArr = $Res['data'];
			if($IsEnd != $OldPartArr['part_is_end'])
			{//改变了是否为末级
				if($IsEnd == 0)
				{//设为非末级，检测是否有产品
					$Res = $this->getProCount($PartId);
					if(!$Res['status'])
					{
						return LibFc::ReturnData(false, $Res['data']);
					}
					else if($Res['data']['count'] > 0)
					{
						return LibFc::ReturnData(false, '该零件下有'.$Res['data'].'个产品，必须设置为末级！');
					}
				}
				else
				{//设为末级，检测是否有子分类
					$Res = $this->getPartByPid($PartId);
					if(!$Res['status'])
					{
						return LibFc::ReturnData(false, $Res['data']);
					}
					else if(count($Res['data']) > 0)
					{
						return LibFc::ReturnData(false, '该零件下有'.count($Res['data']).'个子零件，不能设置为末级！');
					}
				}
			}

			$Res = $this->Get('bc_part_tree',['*'] ,' and pt_part_id='.$PartId);
			if(!$Res['status'])
			{
				return LibFc::ReturnData(false, $Res['data']);
			}
			$OldParentArr = array();
			$SetIdArr = array();
			$DelIdArr = array();
			foreach($Res['data'] as $V)
			{
				$OldParentArr[] = $V['pt_parent_part_id'];
				if(!in_array($V['pt_parent_part_id'], $ParentArr))
				{//旧的不存在于新的 删除
					$DelIdArr[] = $V['pt_parent_part_id'];
				}
			}
			$AddParentIdArr = array();
			foreach($ParentArr as $Id)
			{
				if(!in_array($Id, $OldParentArr))
				{//新不存在于旧的 新增
					$AddParentIdArr[] = $Id;
				}
			}		
			//取出该零件下的子零件并去重
			$childrenPartData=$this->getFieldUniVal('bc_part_tree','pt_part_id',' and pt_parent_part_id='.$PartId);
			//删除不存在的父类
			$delPath=array();
			$this->B2CDb->Begin();
			if(!empty($DelIdArr))
			{
				foreach ($DelIdArr as $id) 
				{
					$delData=$this->Get('bc_part_tree',['pt_path'],' and pt_part_id='.$id);
					foreach ($delData['data'] as $k => $v) 
					{
						$delPath[]=$v['pt_path'].','.$id.','.$PartId;
					}
					$delWhere=sprintf(' and pt_part_id=%d and pt_parent_part_id=%d',$PartId,$id);
					$this->Del('bc_part_tree',$delWhere);
				}
				//删除不存在的父类的子类，根据路径
				foreach ($delPath as $v) 
				{
					$childWhere=sprintf(" and pt_parent_part_id=%d and pt_path='%s'",$PartId,$v);
					$this->Del('bc_part_tree',$childWhere);
				}				
			}
			//添加新的父类---start	
			$data=array();
			if(count($AddParentIdArr) > 0)
			{
				foreach ($AddParentIdArr as $key => $value) 
				{
					if($value>0)
					{
						$Res=$this->Get('bc_part_tree',['pt_level','pt_path'],' and pt_part_id='.$value);//新添加的父类路径
						foreach ($Res['data'] as $i => $j) 
						{
							$data[$value]['level'][]=$j['pt_level']+1;
							$data[$value]['path'][]=$j['pt_path'].','.$value;
						}
					}
					else
					{
						$data[$value]['level'][]=1;
						$data[$value]['path'][]=0;
					}
				}
				foreach ($data as $key => $value) 
				{
					//每个父类对应多条路径
					foreach ($value['level'] as $i => $j) 
					{
						$parentTarget=array('pt_part_id'=>$PartId,'pt_parent_part_id'=>$key,'pt_level'=>$j,'pt_path'=>$data[$key]['path'][$i]);
						$this->Add('bc_part_tree',$parentTarget);
						//添加新的子零件
						if(!empty($childrenPartData['data']))
						{
							foreach ($childrenPartData['data'] as $chilPartId) 
							{
								$childPath=$data[$key]['path'][$i].','.$PartId;
								$childTarget=array('pt_part_id'=>$chilPartId,'pt_parent_part_id'=>$PartId,'pt_level'=>($j+1),'pt_path'=>$childPath);
								$this->Add('bc_part_tree',$childTarget);
							}
						}
					}
				}
				
			}		
			//添加新的父类----end
			//统一修改主父类
			$this->Set('bc_part_tree',['pt_ismain'=>0],' and pt_part_id='.$PartId);
			$this->Set('bc_part_tree',['pt_ismain'=>1],sprintf(' and pt_part_id=%d and pt_parent_part_id=%d',$PartId,$MainParent));
			$this->B2CDb->End();
			return LibFc::ReturnData(true,true);
		}
		return LibFc::ReturnData(false, '提供的参数不正确。');
	}
	/**
	 * @method    修改零件基本信息
	 * @param     [int]       $PartId   [零件ID]
	 * @param     [string]       $partName [零件名]
	 * @param     [string]       $Keyword  [关键字]
	 * @return   [array] [array('status'=>true,'data'=>true)]
	 * @author 卢
	 * @copyright 2017-07-17
	 */
	public function setPartBasic($PartId, $baseArr)
	{
		$PartId = LibFc::Int($PartId);
		if($PartId > 0 && !empty($baseArr['part_name']))
		{
			//检测是否重复
			$Res = $this->checkPart(array('part_name'=>$baseArr['part_name'], 'part_is_end'=>$baseArr['part_is_end']), $PartId);
			// print_r($Res);
			if(!$Res['status'])
			{
				return LibFc::ReturnData(false, $Res['data']);
			}
			else if($Res['data']['count'] > 0)
			{
				return LibFc::ReturnData(false, '零件已经存在。');
			}
			$baseArr['part_initial'] = LibFc::GetInitial($baseArr['part_name']);
			$this->B2CDb->Begin();
			if($baseArr['part_is_end']==0)
			{
				//设为非末级,删除下面的参数
				$labelData=$this->getFieldUniVal('bc_part_param_link','ppl_pal_id',' and ppl_part_id='.$PartId);
				if(!empty($labelData['data']))
				{
					$this->Del('bc_param_label',sprintf(' and pal_id in (%s)',implode(',',$labelData['data'])));
					$this->Del('bc_part_param_link',' and ppl_part_id='.$PartId);
				}
			}
			
			if(isset($baseArr['part_sup_names']))
			{
				$baseArr['part_sup_names'] = array_unique(explode(',', $baseArr['part_sup_names']));
				sort($baseArr['part_sup_names']);
				$res = $this->getSupIdsByNames($baseArr['part_sup_names']);
				$baseArr['part_sup_names'] = implode(',', $baseArr['part_sup_names']);
				$baseArr['part_sup_ids_tcdcn'] = implode(',', $res['data']['tcdcn']);
			}

			if(isset($baseArr['part_opart_names']))
			{
				$baseArr['part_opart_names'] = array_unique(explode(',', $baseArr['part_opart_names']));
				sort($baseArr['part_opart_names']);
				$res = $this->getPartIdsByNames($baseArr['part_opart_names']);
				$baseArr['part_opart_names'] = implode(',', $baseArr['part_opart_names']);
				$baseArr['part_opart_ids_tcdcn'] = implode(',', $res['data']['tcdcn']);
			}

			$this->Set('bc_part', $baseArr,' and part_id='.$PartId);
			$this->B2CDb->End();
			return LibFc::ReturnData(true, $PartId);
		}
		return LibFc::ReturnData(false, '提供的参数不正确。');
	}
	/**
	 * @method    根据路径获取配件分类
	 * @param     string        $path [分类路径]
	 * @return    [array]              
	 * @author 卢
	 * @copyright 2017-10-17
	 */
	public function getPartByPath($path='0')
	{
		$where=sprintf(" and pt_path='%s'",LibFc::Escape($path));
		$res=$this->Get('bc_part left join bc_part_tree on pt_part_id=part_id',['pt_part_id','part_name','part_is_end','pt_ismain','pt_path'],$where);
		return $res;
	}
	/**
	 * @method    递归获取分类树（已分组）
	 * @param     [arr]       $tree [所有配件]
	 * @param     int      $path [配件父ID]
	 *@param   $[name] [<description>][array]      [['status'=>true,'data'=>[0=>['pt_part_id'=>1,'PT_part_name'=>发动机,xxxx]],xxx]
	 * @author 卢
	 * @copyright 2017-10-17
	 */
	public function getPartChild($tree,$path=0)
	{
		if(is_array($tree))
		{
			$data=array();
			foreach ($tree as $key => $value) 
			{
				if($value['pt_parent_part_id']==$path)
				{
					$data[$value['pt_part_id']][]=$value;
					$res=$this->getPartChild($tree,$value['pt_part_id']);
					$temp=[];
					if(count($res['data']))
					{
						foreach ($res['data'] as $i=> $v) 
						{
							$temp=array_merge($temp,$v);
						}
					}
					$data[$value['pt_part_id']]=array_merge($data[$value['pt_part_id']],$temp);
				}
			}
			return LibFc::ReturnData(true,$data);
		}
		return LibFc::ReturnData(false,'参数不正确');
	}
	/**
	 * @method    转移零件分类
	 * @param     [arr]     $dataArr [需要转移的分类ID]
	 * @param     [int]     $target  [转移的目标ID]
	 * @return    [bool]             
	 * @author 卢
	 * @copyright 2018-06-07
	 */
	public function changePart($dataArr,$target)
	{
		if(!empty($dataArr)&&LibFc::Int($target))
		{
			$dataArr=array_filter($dataArr);
			//剔除目标分类
			if(($key=array_search($target, $dataArr))!==false)
			{
				unset($dataArr[$key]);
			}
			//检查是否末级分类
			$tempArr=$dataArr;
			array_push($tempArr, $target);
			$res=$this->get('bc_part',['part_id'],sprintf(' and part_id in(%s) and part_is_end>0',implode(',',$tempArr)));
			$oriArr=array_column($res['data'], 'part_id');
			foreach ($dataArr as $k=> $v) 
			{
				if(!in_array($v, $oriArr)||empty($v))
					unset($dataArr[$k]);
			}
			if(!in_array($target, $oriArr))
				return LibFc::ReturnData(false,'目标分类非末级，合并失败');

			$res=$this->get('bc_part_small',['pas_id'],sprintf(' and pas_part_id in(%s)',implode(',',$dataArr)));
			if(!empty($res['data'])) return LibFc::ReturnData(false,'被合并的分类有子类，禁止合并');

			$res=$this->get('bc_part_param_link',['ppl_part_id'],sprintf(' and ppl_part_id in(%s)',implode(',',$dataArr)));
			if(!empty($res['data'])) return LibFc::ReturnData(false,'被合并的分类有参数，禁止合并');

			$tempArr=$dataArr;
			array_push($tempArr, $target);
			//关键字
			$res=$this->get('bc_part',["part_keyword"],sprintf(' and part_id in(%s)',implode(',',$tempArr)));
			if(!empty($res))
			{
				$keyword='';
				foreach ($res['data'] as $v) 
				{
					$keyword.=','.$v['part_keyword'];
				}
				$keyword=trim($keyword,',');
			}
			//目标分类路径
			$res=$this->get('bc_part_tree',['pt_path'],sprintf(' and pt_part_id=%d and pt_ismain>0',$target),true);
			$path=$res['data']['pt_path'].','.$target;
			$this->B2CDb->Begin();
			////转移配件分类
			$this->set('bc_product',['pro_part_id'=>$target,'pro_part_path'=>$path],sprintf(' and pro_part_id in(%s)',implode(',',$dataArr)));
			//删除配件参数值
			$this->del('bc_product_param_float',sprintf(' and ppf_pro_id in(select pro_id from bc_product where pro_part_id in(%s))',implode(',',$dataArr)));
			$this->del('bc_product_param_string',sprintf(' and pps_pro_id in(select pro_id from bc_product where pro_part_id in(%s))',implode(',',$dataArr)));

			//删除参数值
			$this->del('bc_param_value',sprintf(' and pav_part_id in(%s)',implode(',',$dataArr)));
			//删除参数名
			$this->del('bc_param_label',sprintf(' and pal_id in(select ppl_pal_id from bc_part_param_link where ppl_part_id in(%s))',implode(',',$dataArr)));
			//删除分类与参数对应关系表
			$this->del('bc_part_param_link',sprintf(' and ppl_part_id in(%s)',implode(',',$dataArr)));

			//删除分类树
			$this->del('bc_part_tree',sprintf(' and pt_part_id in(%s)',implode(',',$dataArr)));
			//删除分类
			$this->del('bc_part',sprintf(' and part_id in(%s)',implode(',',$dataArr)));
			//更新关键字
			if(!empty($keyword))
			{
				$this->set('bc_part',['part_keyword'=>$keyword],sprintf(' and part_id=%d',$target));
			}
			$this->B2CDb->End();

			return LibFc::ReturnData(true,true);
		}
		return LibFc::ReturnData(false,'changePart 参数不正确');
	}

	/**
	 * @method    getSaleTopPart 获取销售排行
	 * @author    liao
	 * @copyright 2018-09-20
	 * @return    ['id'=>'xxx','id'=>'xxx',...]
	 */
	public function getSaleTopPart()
	{
		// 判断缓存文件是否存在
		$file = mvc::$cfg['AUTOLOAD']['B2c']['path'].'cache/saleTop.php';
		if(!file_exists($file) || filemtime($file) < (time()-3600))
		{
			$where = " and orp_status='completed' and shop_istest=0";
			$table = 'or_order_product left join bc_product on pro_id=orp_pro_id left join sh_shop on pro_shop_id=shop_id';
			//总数计算
			$res = $this->get($table,['count(pro_part_id) count','pro_part_id'],$where.' group by pro_part_id');
			//默认分类
			$saletop = mvc::$cfg['SALETOP'];
			//去空过滤
			$res = array_filter($res['data'],function($val){if(empty($val['pro_part_id'])){return false;}else{return true;}});
			if(!empty($res))
			{
				//根据销量排序
				$res = array_column($res, 'count', 'pro_part_id');
				arsort($res);
				//取出目标分类 并计算长度 默认 5 个 分类 不够则补充完整
				$res = array_keys($res);
				$res = array_slice($res, 0, 5);
				$count = count($res);
				if($count < 5 && is_array($saletop))
				{
					$diff = array_diff($saletop, $res);
					//补充长度
					$res = array_merge($res, array_slice($diff, 0, 5-$count));
				}
			}else
			{
				$res = $saletop;
			}
			//保存缓存文件
			LibFc::ArraySave($res, $file);
		}else
		{
			$res = include($file);
		}
		return LibFc::ReturnData(true,$res);
	}



	/**
	  * @method 保存零件分类的子类
	  * @param  $partId 分类ID
	  * @param  $smallArr 子零件
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function setPartSmallPart($partId, $smallArr)
	{
		$res = $this->get('bc_part', ['*'], sprintf(" and part_id=%d", $partId), true);
		if(empty($res['data'])) return LibFc::ReturnData(false, '零件分类不存在！');
		$partArr = $res['data'];
		
		$res = $this->get('bc_part_small', ['*'], sprintf(" and pas_part_id=%d", $partArr['part_id']));
		$hasArr = array_column($res['data'], 'pas_id');

		$this->B2CDb->Begin();
		if(empty($partArr['part_is_end']))
		{
			$delArr = $hasArr;
		}
		else
		{
			$delArr = array_diff($hasArr, array_keys($smallArr));
			$seq = 0;
			foreach($smallArr as $id=>$v)
			{
				$seq++;
				if(!empty($v['pas_name']))
				{
					$v['pas_part_id'] = $partId;
					$v['pas_seq'] = $v['pas_seq'] == '' ? $seq: (int) $v['pas_seq'];
					if($id > 0)
					{
						$this->set('bc_part_small', $v, sprintf(" and pas_id=%d", $id));
					}
					else
					{
						$res = $this->add('bc_part_small', $v);
						$v['pas_id'] = $res['data'];
					}
				}
			}
		}
		if(!empty($delArr))
		{
			$this->set('bc_product', ['pro_pas_id'=>0], sprintf(" and pro_pas_id in (%s)", implode(',', $delArr)));
			$this->del('bc_part_small', sprintf(" and pas_id in (%s)", implode(',', $delArr)));
		}
		$this->B2CDb->End();
		return LibFc::ReturnData(true);
	}


	/**
	  * @method 通过名称匹配出厂商ID
	  * @param  $wordArr ['TRW', 'ATE'....]
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function getSupIdsByNames($wordArr)
	{
		$formatArr = [];
		foreach($wordArr as $k=>$v)
		{
			$v = strtoupper(trim($v));
			if($v != '')
			{
				$formatArr[] = $v;
			}
		}
		$arr = ['tcdcn'=>[]];
		if(!empty($formatArr))
		{
			$TcdcnItem = new TcdcnItem();
			$res = $TcdcnItem->getFormatSup();
			$allformat = $res['data'];
			foreach($formatArr as $v)
			{
				if(!empty($allformat[$v]))
					$arr['tcdcn'] = array_merge($arr['tcdcn'], $allformat[$v]);
			}
			$arr['tcdcn'] = array_unique($arr['tcdcn']);
		}
		return LibFc::ReturnData(true, $arr);
	}


	/**
	  * @method 通过名称匹配出零件分类ID
	  * @param  $wordArr ['刹车片', '前刹车片'....]
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function getPartIdsByNames($wordArr)
	{
		$formatArr = [];
		foreach($wordArr as $k=>$v)
		{
			$v = strtoupper(trim($v));
			if($v != '')
			{
				$formatArr[] = $v;
			}
		}
		$arr = ['tcdcn'=>[]];
		if(!empty($formatArr))
		{
			$TcdcnItem = new TcdcnItem();
			$res = $TcdcnItem->getFormatPart();
			$allformat = $res['data'];
			foreach($formatArr as $v)
			{
				if(!empty($allformat[$v]))
					$arr['tcdcn'] = array_merge($arr['tcdcn'], $allformat[$v]);
			}
			$arr['tcdcn'] = array_unique($arr['tcdcn']);
		}
		return LibFc::ReturnData(true, $arr);
	}



	/**
	  * @method 获取商家的超级目录配件分类
	  * @param  $shopId 店铺ID
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function getShopSuperPart($shopId, $filedArr = ['part_id', 'part_name'])
	{
		$table = 'sh_super_part join bc_part on sup_part_id = part_id join bc_part_tree ON pt_part_id = part_id and pt_ismain=1 ';
		return $this->get($table, $filedArr, sprintf(" and sup_shop_id=%d ORDER BY pt_seq, part_initial", $shopId));
	}


	/**
	  * @method 获取商家的目录子配件分类
	  * @param  $shopId 店铺ID
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function getShopSuperSPart($shopId)
	{
		$arr = [];
		$table = 'sh_super_part 
		join bc_part on sup_part_id = part_id 
		join bc_part_tree ON pt_part_id = part_id and pt_ismain=1
		left join bc_part_small on  part_id = pas_part_id';
		$res = $this->get($table, ['part_id, part_name, pas_id, pas_name,pt_path'], sprintf(" and sup_shop_id=%d ORDER BY pt_seq, part_initial, pas_seq", $shopId));
		foreach($res['data'] as $v)
		{
			if(!empty($v['pas_id']) && empty($arr[$v['part_id'].'_0']))
			{
				$t = $v;
				$t['id'] = $t['part_id'].'_0';
				$t['name'] = $t['part_name'];
				$t['pas_id'] = 0;
				$t['pas_name'] = '';
				$arr[$t['id']] = $t;
			}
			$v['id'] = $v['part_id'].'_'.((int) $v['pas_id']);
			$v['name'] = empty($v['pas_name'])? $v['part_name']: $v['pas_name'];
			$arr[$v['id']] = $v;
		}
		return LibFc::ReturnData(true, array_values($arr));
	}

	/**
	  * @method 获取商家的目录参数查询分类
	  * @param  $shopId 店铺ID
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function getShopSuperParaPart($shopId)
	{
		$arr = [];
		$table = 'sh_super_part 
		join bc_part on sup_part_id = part_id 
		join bc_part_tree ON pt_part_id = part_id and pt_ismain=1';
		$res = $this->get($table, ['part_id as id, part_name as name'], sprintf(" and part_asuper_search_para=1 and sup_shop_id=%d ORDER BY pt_seq, part_initial", $shopId));
		foreach($res['data'] as $v)
		{
			$arr[] = $v;
		}
		return LibFc::ReturnData(true, $arr);
	}

	


	/**
	  * @method 获取商家可以使用的TCD中国数据分类和厂商ID
	  * @param  $shopId 店铺ID
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function getShopSuperTcdCnOpt($shopId, $spartId = '')
	{
		$where = sprintf(" and sup_shop_id=%d", $shopId);
		if(!empty($spartId))
		{
			$t = explode('_', $val);
			$where .= sprintf(" and part_id=%d", $t[0]);
		}
		$arr = ['partids'=>[], 'supids'=>[]];
		$table = 'sh_super_part join bc_part on sup_part_id = part_id';
		$res = $this->get($table, ['part_sup_ids_tcdcn, part_opart_ids_tcdcn'], $where);
		foreach($res['data'] as $v)
		{
			if(!empty($v['part_sup_ids_tcdcn'])) $arr['supids'] = array_merge($arr['supids'], explode(',', $v['part_sup_ids_tcdcn']));
			if(!empty($v['part_opart_ids_tcdcn'])) $arr['partids'] = array_merge($arr['partids'], explode(',', $v['part_opart_ids_tcdcn']));
		}
		return LibFc::ReturnData(true, $arr);
	}
	
	/**
	  * @method 零件和车型信息的字段
	  * @author soul
	  * @copyright 2019/7/12
	  * @return ["status"=> bool(true), "data"=> true, "code"=>""]
	  */
	public function partModelFiled()
	{
		$arr = [
			'mod3_engine'=>'发动机',
			'mod3_kw'=>'功率',
			'mod3_cc'=>'排量',
			'mod3_transmission'=>'变速器',
			'mod3_front_brake'=>'前制动器',
			'mod3_rear_brake'=>'后制动器',
			'mod3_parking_brake'=>'驻车制动'
		];
		return LibFc::ReturnData(true, $arr);
	}

	/**
	 * @method 获取配件中的分类
	 * @param  $shopId 店铺ID
	 * @param  $mode 默认：输出配件中的全部分类,bind:只输出产品绑定的分类
	 * @author zhengweihua 
	 * @copyright 2022-05-23
	 */
	public function getProductPart($shopId,$mode='')
	{
		$where = sprintf(' and part_id in (select pro_part_id from bc_product where pro_shop_id=%d)',$shopId);
		$where .= ' order by pt_seq, part_initial ';
		$res = $this->get('bc_part 
		join bc_part_tree on part_id = pt_part_id and pt_ismain=1 
		left join bc_part_small on part_id = pas_part_id ', ['part_id', 'part_name','pt_parent_part_id','pas_id','pas_name'], $where);
		$arr = [];
		foreach($res['data'] as $v)
		{
			$t = [];
		
			if(empty($arr[$v['part_id']])){

				$t['id'] = $v['part_id'];
				$t['spart_id'] = $v['part_id'].'_0';
				$t['name'] = $v['part_name'];
				$t['pId']  = $v['pt_parent_part_id'];
				$t['checked'] = true;
				$arr[$t['id']] = $t;
				
			}
			if(!empty($v['pas_id'])){
				$t['id'] = ((int) $v['pas_id']);
				$t['name'] = $v['pas_name'];
				$t['pId'] = $v['part_id'];
				$t['spart_id'] = $v['part_id'].'_'. ((int) $v['pas_id']);
				$t['checked'] = true;
				$arr[$v['pas_id']] = $t;
			}
			
		}
		$arr = array_values($arr);
		//筛选出绑定有产品的分类
		if($mode=='bind')
		{
			$res = $this->get('bc_product',["concat(pro_part_id,'_',pro_pas_id) as spartId"],sprintf(" AND pro_shop_id=%d",$shopId));
			$spartIdArr = array_unique(array_column($res['data'],'spartId'));
			foreach ($arr as $key => $val) {
				if(!in_array($val['spart_id'],$spartIdArr)){
					unset($arr[$key]);
				}
			}
		}
		return  LibFc::ReturnData(true,$arr);		
	}
}