* +---------------------------------------------------------------------- */ namespace App\Http\Dao\Client; use App\Constants\CustomEnum\CustomerEnum; use App\Http\Dao\BaseDao; use App\Http\Model\BaseModel; use App\Http\Model\Client\ClientFollow; use App\Http\Model\Client\Customer; use App\Http\Model\Schedule\ScheduleRemind; use App\Http\Model\Schedule\ScheduleTask; use App\Http\Service\Client\ClientSubscribeService; use App\Http\Service\Client\ContractService; use App\Http\Service\Client\Custom\CommonService; use App\Http\Service\Client\CustomerLiaisonService; use crmeb\traits\dao\BatchSearchTrait; use crmeb\traits\dao\JoinSearchTrait; use crmeb\traits\dao\ListSearchTrait; use crmeb\traits\dao\TogetherSearchTrait; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Database\Concerns\BuildsQueries; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Schema; use Illuminate\Support\HigherOrderWhenProxy; use Illuminate\Support\Str; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; /** * class CustomerDao. */ class CustomerDao extends BaseDao { use CommonService; use ListSearchTrait; use TogetherSearchTrait; use BatchSearchTrait; use JoinSearchTrait; protected $otherSearch = [ 'statistics_type', 'types', 'scope_frame', 'before_salesman', 'customer_repeat_check', 'subscribe_uid', ]; /** * 设置模型. * @return BaseModel * @throws BindingResolutionException */ public function getModel(bool $need = true) { $model = parent::getModel(); $tableName = 'customer_' . $this->entId; $this->createTableIfNotExists($tableName); $model = $model->setTable($tableName); if ($need && $this->entId && Schema::hasColumn($tableName, 'entid')) { $model = $model->where($tableName . '.entid', $this->entId); } return $model; } /** * 创建表. * @return void */ private function createTableIfNotExists(string $tableName) { if (!Schema::hasTable($tableName)) { Schema::create($tableName, function (Blueprint $table) { $table->bigIncrements('id'); $table->integer('uid')->default(0)->comment('业务员ID'); $table->unsignedInteger('entid')->default($this->entId)->index()->comment('企业ID'); $table->integer('before_uid')->default(0)->comment('前业务员ID'); $table->integer('creator_uid')->default(0)->comment('创建人ID'); $table->string('customer_name')->default('')->comment('客户名称'); $table->string('customer_label')->default('""')->comment('客户标签'); $table->string('customer_no', 15)->default('')->comment('客户编号'); $table->string('customer_way')->default('""')->comment('客户来源'); $table->integer('un_followed_days')->default(0)->comment('未跟进天数'); $table->decimal('amount_recorded', 10)->default(0)->comment('已入账金额'); $table->decimal('amount_expend', 10)->default(0)->comment('已支出+金额'); $table->decimal('invoiced_amount', 10)->default(0)->comment('已开票金额'); $table->integer('contract_num')->default(0)->comment('合同数量'); $table->integer('invoice_num')->default(0)->comment('发票数量'); $table->integer('attachment_num')->default(0)->comment('附件数量'); $table->integer('return_num')->default(0)->comment('退回次数'); $table->string('customer_followed')->default('1')->comment('是否关注'); $table->string('customer_status')->default('0')->comment('客户状态'); $table->string('area_cascade')->default('""')->comment('省市区'); $table->string('b37a3f36')->default('')->comment('备注'); $table->string('b37a3f16')->default('')->comment('企业电话'); $table->string('9bfe77e4')->default('')->comment('详细地址'); $table->string('7763f80f')->default('')->comment('客户附件'); $table->string('c839a357')->default('')->comment('备注'); $table->timestamp('last_follow_up_time')->nullable()->comment('最后跟进时间'); $table->timestamp('collect_time')->nullable()->comment('领取时间'); $table->timestamps(); $table->softDeletes(); }); } } /** * 搜索. * * @param array|int|string $where * * @return BaseModel|BuildsQueries|mixed * @throws \ReflectionException * @throws BindingResolutionException */ public function search($where, ?bool $authWhere = null) { return parent::search($where, $authWhere); } /** * 待办关联查询. * @return BaseModel|HigherOrderWhenProxy|mixed * @throws BindingResolutionException */ public function scheduleSearch($where): mixed { $remindDay = Carbon::now(config('app.timezone'))->toDateString(); $this->aliasC = app()->get($this->setModelC())->getTable(); $this->aliasD = app()->get($this->setModelD())->getTable(); return $this->getJoinModel('id', 'eid') ->join($this->aliasC, $this->aliasB . '.uniqued', '=', $this->aliasC . '.uniqued') ->join($this->aliasD, $this->aliasC . '.sid', '=', $this->aliasD . '.pid', 'left') ->where($this->getFiled('uid'), '<>', 0) ->where($this->getFiled('types', $this->aliasB), 1) ->whereDate($this->getFiled('time', $this->aliasB), '<', $remindDay) ->where(function ($query) use ($where) { $uidField = $this->getFiled('uid'); if (isset($where['uid']) && $where['uid']) { if (is_array($where['uid'])) { $query->whereIn($uidField, $where['uid']); } else { $query->where($uidField, $where['uid']); } } }) ->where(function (Builder $query) { $query->where($this->getFiled('status', $this->aliasD), '<>', 3); $query->orWhereNull($this->getFiled('id', $this->aliasD)); }); } /** * 急需跟进统计. * @throws BindingResolutionException */ public function getUrgentFollowUpCount(array $where): int { return $this->scheduleSearch($where)->select(['customer_'.$this->entId.'.id'])->distinct()->get()->map(function ($item) { return $item['id']; })->count(); } /** * 列表筛选数据. * @return Builder * @throws BindingResolutionException */ public function listSearch($where, $page = 0, $limit = 0, $with = []) { $dao = $this->getModel(false); $where = $this->getWhere($where, CustomerEnum::CUSTOMER); foreach ($where as $field => $value) { if ($value === '') { continue; } if (in_array($field, $this->otherSearch)) { switch ($field) { case 'statistics_type': switch ($value) { case 'concern': $ids = app()->get(ClientSubscribeService::class)->column(['uid' => $where['subscribe_uid'], 'subscribe_status' => 1], 'eid'); $dao = $dao->whereIn('id', $ids); break; case 'unsettled': $dao = $dao->where('customer_status', 0); break; case 'traded': $dao = $dao->where('customer_status', 1); break; case 'urgent_follow_up': $ids = $this->scheduleSearch(['uid' => $where['uid']])->select(['customer.id'])->distinct()->get(); $dao = $dao->whereIn('id', $ids); break; } // no break case 'scope_frame': break; case 'types': if ($value != 3) { $dao = $dao->where('customer_status', '<', 2); } break; case 'before_salesman': $dao = $this->searchBeforeSalesman($dao, $value['value']); break; case 'customer_repeat_check': $dao = $dao->where('customer_name', 'like', "%{$value}%"); break; } unset($where[$field]); } else if (is_array($value)) { if (isset($value['input_type'])) { $dao = match ($value['input_type']) { 'select', 'checked', 'radio' => $this->getSelectSearch($dao, $field, $value['value']), 'input' => $this->getInputSearch($dao, $field, $value['value']), 'date' => $this->getDateSearch($dao, $field, $value['value']), 'personnel' => $this->getPersonnelSearch($dao, $field, $value['value']), default => $dao->where($field, $value['value']), }; } else { $dao = $dao->whereIn($field, $value); } } else { $dao = $dao->where($field, $value); } } return $dao->when($page && $limit, function ($query) use ($page, $limit) { $query->forPage($page, $limit); })->when($sort = sort_mode('id'), function ($query) use ($sort) { if (is_array($sort)) { foreach ($sort as $k => $v) { if (is_numeric($k)) { $query->orderByDesc($v); } else { $query->orderBy($k, $v); } } } else { $query->orderByDesc($sort); } })->with($with); } /** * 合同名称查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchContractName($dao, $value) { $ids = app()->get(ContractService::class)->column(['contract_name' => $value], 'eid'); return $dao->whereIn('id', $ids); } /** * 业务员查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchSalesman($dao, $value) { return $dao->whereIn('uid', $value); } /** * 合同编号查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchContractNo($dao, $value) { $ids = app()->get(ContractService::class)->column(['contract_no' => $value], 'eid'); return $dao->whereIn('id', $ids); } /** * 联系人电话查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchLiaisonTel($dao, $value) { $ids = app()->get(CustomerLiaisonService::class)->column(['liaison_tel' => $value], 'eid'); return $dao->whereIn('id', $ids); } /** * 联系人电话查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchLiaison($dao, $value) { $ids = app()->get(CustomerLiaisonService::class)->column(['liaison_name' => $value], 'eid'); return $dao->whereIn('id', $ids); } /** * 省市区查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchAreaCascade($dao, $value) { $data = []; foreach ($value as $item) { $item = is_array($item) ? $item : json_decode($item, true); $data[] = (string)end($item); } return $dao->where(function ($query) use ($data) { foreach ($data as $item) { $query->orWhere('area_cascade', 'like', "%\"{$item}\"%"); } }); } /** * 客户标签查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchCustomerLabel($dao, $value) { return $dao->where(function ($q) use ($value) { foreach ($value as $v) { $q->orWhere('customer_label', 'like', "%\"{$v}\"%"); } }); } /** * 客户创建人查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchCreator($dao, $value) { return $dao->whereIn('creator_uid', $value); } /** * 客户标签查询. * @return mixed * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function searchBeforeSalesman($dao, $value) { return $dao->whereIn('before_uid', $value); } /** * 急需跟进ID. * @throws BindingResolutionException */ public function getUrgentFollowUpIds(array $where): array { return $this->scheduleSearch($where)->select(['customer_'.$this->entId.'.id'])->distinct()->get()->map( function ($item) { return $item['id']; } )->toArray(); } /** * 跟进过期客户. * @throws BindingResolutionException */ public function getFollowExpire(array $where): mixed { return $this->scheduleSearch($where)->select(['customer_'.$this->entId.'.id'])->distinct()->get()->map(function ($item) { return $item['id']; }); } protected function setModel(): string { return Customer::class; } protected function setModelB(): string { return ClientFollow::class; } protected function setModelC(): string { return ScheduleRemind::class; } protected function setModelD(): string { return ScheduleTask::class; } private function getInputSearch($dao, $field, $value) { if (method_exists($this, 'search' . Str::studly($field))) { return $this->{'search' . Str::studly($field)}($dao, $value); } return $dao->where($field, 'like', "%{$value}%"); } private function getSelectSearch($dao, $field, $value) { if (method_exists($this, 'search' . Str::studly($field))) { return $this->{'search' . Str::studly($field)}($dao, $value); } return is_array($value) ? $dao->whereIn($field, $value) : $dao->where($field, $value); } private function getPersonnelSearch($dao, $field, $value) { if (method_exists($this, 'search' . Str::studly($field))) { return $this->{'search' . Str::studly($field)}($dao, $value); } return $dao->whereIn($field, $value); } }