1
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\controller;
|
||||
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\exception\BusinessException;
|
||||
use app\common\traits\ResponseTrait;
|
||||
use think\Validate;
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected mixed $validator = null;
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
*
|
||||
* @param Validate $validator 验证器实例
|
||||
* @param array $data 待验证的数据
|
||||
* @param string $scene 验证场景
|
||||
* @return array 验证后的数据
|
||||
* @throws BusinessException 验证失败时抛出业务异常
|
||||
*/
|
||||
public function validate(Validate $validator, array $data, string $scene = ''): array
|
||||
{
|
||||
// 如果指定了验证场景,并且验证器支持场景方法,则设置验证场景
|
||||
if ($scene && method_exists($validator, 'scene')) {
|
||||
$validator->scene($scene);
|
||||
}
|
||||
// 执行数据验证
|
||||
if (!$validator->check($data)) {
|
||||
// 验证失败,抛出业务异常,异常信息为验证器返回的错误信息
|
||||
throw new BusinessException($validator->getError());
|
||||
}
|
||||
// 验证成功,返回原始数据
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function page($result){
|
||||
$current = $result->currentPage();
|
||||
$total = $result->total();
|
||||
$size = $result->perPage();
|
||||
$result = $result->toArray();
|
||||
$result['current'] = $current;
|
||||
$result['total'] = $total;
|
||||
$result['size'] = $size;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\crm\controller\BaseController;
|
||||
use app\crm\model\CarType;
|
||||
use app\crm\model\Customer;
|
||||
use app\crm\utils\Util;
|
||||
use PDO;
|
||||
use support\Db;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class CarTypeController extends BaseController
|
||||
{
|
||||
|
||||
public function getAll(Request $request)
|
||||
{
|
||||
$list = CarType::getAll();
|
||||
|
||||
if($request->user['language'] != 'zh_CN'){
|
||||
foreach ($list as &$value) {
|
||||
$value['name'] = $value['name_en'];
|
||||
}
|
||||
}elseif ($request->user['language'] == 'ru'){
|
||||
foreach ($list as &$value) {
|
||||
$value['name'] = $value['name_ru'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success($list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\controller;
|
||||
|
||||
use app\crm\model\Customer;
|
||||
use app\crm\model\User;
|
||||
use app\crm\service\CustomerService;
|
||||
use app\crm\utils\Util;
|
||||
use support\Request;
|
||||
|
||||
class CustomerController extends BaseController
|
||||
{
|
||||
/**
|
||||
* 客户列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
try {
|
||||
$result = (new CustomerService())->list($request->all());
|
||||
return $this->success($this->page($result));
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function follow(Request $request)
|
||||
{
|
||||
// try {
|
||||
// $result = (new CustomerService())->follow($request->all());
|
||||
// return $this->success($this->page($result));
|
||||
// } catch (\Throwable $e) {
|
||||
// return $this->error($e->getMessage());
|
||||
// }
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$where = [];
|
||||
if($request->input('user_id')){
|
||||
$where[] = ['user_id', '=', $request->input('user_id')];
|
||||
}
|
||||
$user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page);
|
||||
$user = $user->toArray();
|
||||
foreach ($user['data'] as &$item) {
|
||||
unset($item['password']);
|
||||
}
|
||||
return $this->success($user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\controller;
|
||||
|
||||
use app\crm\model\Customer;
|
||||
use app\crm\model\Follow;
|
||||
use app\crm\service\CustomerService;
|
||||
use app\crm\service\FollowService;
|
||||
use app\crm\utils\Util;
|
||||
use app\crm\validate\FollowValidate;
|
||||
use config\constants\Constants;
|
||||
use support\Request;
|
||||
|
||||
class FollowController extends BaseController
|
||||
{
|
||||
/**
|
||||
* 客户分级
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getFollowType(Request $request)
|
||||
{
|
||||
$grade = [];
|
||||
foreach (Constants::FOLLOW as $key => $value) {
|
||||
$grade[] = [
|
||||
'status' => $key,
|
||||
'text' => $value,
|
||||
];
|
||||
}
|
||||
return $this->success($grade);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 跟进列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $this->validate(new FollowValidate(), $request->get(), 'upwd_list');
|
||||
$result = (new FollowService())->list($request->all());
|
||||
return $this->success($this->page($result));
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跟进详情
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function detail(Request $request)
|
||||
{
|
||||
//跟进id
|
||||
$id = Util::getParam($request,'id');
|
||||
if(Util::isEmpty($id)){
|
||||
return $this->error('id'.trans('not_null'));
|
||||
}
|
||||
|
||||
$res = Follow::select('id','user_id','customer_id','type','picture','remark','audio','audio_text','lat','lng','address')
|
||||
->where('id',$id)
|
||||
->first();
|
||||
if($res){
|
||||
$res->toArray();
|
||||
}else{
|
||||
return $this->error('记录不存在');
|
||||
}
|
||||
|
||||
$res = Follow::getFollow($res);
|
||||
|
||||
return $this->success($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户录入
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$customer_id = Util::getParam($request,'customer_id');
|
||||
|
||||
if(Util::isEmpty($customer_id)){
|
||||
return $this->error('customer_id'.trans('not_null'));
|
||||
}
|
||||
$type = Util::getParam($request,'type');
|
||||
if(Util::isEmpty($type)){
|
||||
return $this->error('type'.trans('not_null'));
|
||||
}
|
||||
$picture = Util::getParam($request,'picture');
|
||||
if(Util::isEmpty($picture)){
|
||||
return $this->error(trans('picture_not_null'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'user_id'=>$request->user['id'],
|
||||
'customer_id'=>$customer_id,
|
||||
'type'=>$type,
|
||||
'picture'=>$picture,
|
||||
'remark'=>Util::getParam($request,'remark',''),
|
||||
'audio'=>Util::getParam($request,'audio',''),
|
||||
'audio_text'=>Util::getParam($request,'audio_text',''),
|
||||
'lat'=>Util::getParam($request,'lat',0),
|
||||
'lng'=>Util::getParam($request,'lng',0),
|
||||
'address'=>Util::getParam($request,'address'),
|
||||
'follow_time'=>strtotime(Util::getParam($request,'firstFollowtime',0)),
|
||||
];
|
||||
|
||||
$res = Follow::create($data);
|
||||
|
||||
$customer = Customer::find($customer_id);
|
||||
$customer->follow_last = strtotime($res->created_at);
|
||||
$customer->follow_next = null;
|
||||
$customer->warn = 0;
|
||||
$customer->save();
|
||||
|
||||
if ($res) {
|
||||
return $this->success($res,trans('save_success'));
|
||||
} else {
|
||||
return $this->error(trans('save_fail'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\controller;
|
||||
|
||||
use app\crm\controller\BaseController;
|
||||
use app\crm\model\CustomerTag;
|
||||
use app\crm\model\TagGroup;
|
||||
use app\crm\utils\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Request;
|
||||
|
||||
class TagGroupController extends BaseController
|
||||
{
|
||||
|
||||
// 列表
|
||||
public function list(Request $request)
|
||||
{
|
||||
$list = TagGroup::with('tags')->get();
|
||||
$languageArr = Constants::LANGUAGE;
|
||||
$language = $request->user['language'];
|
||||
foreach ($list as &$item) {
|
||||
$item['names'] = unserialize($item['names']);
|
||||
if (in_array($language, $languageArr)) {
|
||||
$item['name'] = $item['names'][$language];
|
||||
}
|
||||
foreach ($item['tags'] as &$tag) {
|
||||
$tag['names'] = unserialize($tag['names']);
|
||||
if (in_array($language, $languageArr)) {
|
||||
$tag['name'] = $tag['names'][$language];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success($list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新客户标签关系
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function updatePivot(Request $request)
|
||||
{
|
||||
$customerId = Util::getParam($request, 'customer_id');
|
||||
$groupId = Util::getParam($request, 'group_id');
|
||||
$tagId = Util::getParam($request, 'tag_id');
|
||||
if (Util::isEmpty($customerId)) {
|
||||
return $this->error( trans('customer_id') . trans('not_null'));
|
||||
}
|
||||
if (Util::isEmpty($groupId)) {
|
||||
return $this->error( trans('tag_group_id') . trans('not_null'));
|
||||
}
|
||||
|
||||
if(empty($tagId)){
|
||||
$res = CustomerTag::where(['customer_id' => $customerId, 'group_id' => $groupId])->delete();
|
||||
}else{
|
||||
$res = CustomerTag::updateOrCreate(['customer_id' => $customerId, 'group_id' => $groupId], ['tag_id' => $tagId]);
|
||||
}
|
||||
|
||||
if($res){
|
||||
return $this->success($res, trans('success'));
|
||||
}else{
|
||||
return $this->error( trans('fail'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\logic;
|
||||
|
||||
class CustomerLogic
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\logic;
|
||||
|
||||
class FollowLogic
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
|
||||
use support\Model;
|
||||
class CarType extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'car_type';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','name','name_en','status')->where('status',0)->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Channel extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'channel';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
// 'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'updated_at' => 'timestamp', // 指定序列化格式
|
||||
'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','name','name_en','status')->where('status',0)->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Country extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'country';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','cn_addr','en_addr')->get()->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
use app\crm\utils\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Customer extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'customer';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
];
|
||||
|
||||
/**
|
||||
* 重新格式化时间
|
||||
* @param DateTimeInterface $date
|
||||
* @return string
|
||||
*/
|
||||
protected function serializeDate(DateTimeInterface $date): string
|
||||
{
|
||||
return $date->format(Carbon::parse($date)->toDateTimeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $customer
|
||||
* @param $request
|
||||
* @param $tag 是否返回客户标签
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getCustomer($customer, $request, $tag = false)
|
||||
{
|
||||
$language = $request->user['language'] ?: 'en';
|
||||
$customer['grade_txt'] = Util::language($language, Constants::GRADE_EN[$customer['grade']], Constants::GRADE_ZH[$customer['grade']], Constants::GRADE_RU[$customer['grade']]);
|
||||
$customer['magnitude_txt'] = Util::language($language, Constants::MAGNITUDE_EN[$customer['magnitude']], Constants::MAGNITUDE[$customer['magnitude']], Constants::MAGNITUDE_RU[$customer['magnitude']]);
|
||||
$customer['sex_txt'] = Util::language($language, Constants::SEX_EN[$customer['sex']], Constants::SEX[$customer['sex']], Constants::SEX_RU[$customer['sex']]);
|
||||
|
||||
if ($customer['grade']<=2) {
|
||||
$customer['follow'] = 0;
|
||||
$customer['follow_txt'] = Util::language($language,'Following','跟进中','Продолжение');
|
||||
}elseif ($customer['grade']<5) {
|
||||
$customer['follow'] = 1;
|
||||
$customer['follow_txt'] = Util::language($language,'transacted','已成交','Транзакция завершена');
|
||||
}else{
|
||||
$customer['follow'] = 2;
|
||||
$customer['follow_txt'] = Util::language($language,'lost','已流失','Потерянный');
|
||||
}
|
||||
|
||||
$where = [
|
||||
'customer_id' => $customer['id']
|
||||
];
|
||||
$begin_follow = Follow::select('id','created_at','updated_at')
|
||||
->where($where)
|
||||
->min('created_at');
|
||||
|
||||
|
||||
$customer['begin_follow'] = Util::timeTotDate($begin_follow);
|
||||
// $customer['created_at'] = Util::timeTotDate($customer['created_at']);
|
||||
// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']);
|
||||
|
||||
$customer = Util::formatDate($customer,['follow_last']);
|
||||
$nameLang = $language=='en'?'name_en':($language=='ru'?'name_ru':'name');
|
||||
$countryLang = $language=='en'?'en_addr':'cn_addr';
|
||||
$customer['car_type_name'] = empty($customer['car_type_id'])?'':CarType::where(['id'=>$customer['car_type_id']])->value($nameLang);
|
||||
$customer['country_name'] = empty($customer['country_id'])?'':Country::where(['id'=>$customer['country_id']])->value($countryLang);
|
||||
$customer['channel_name'] = empty($customer['channel_id'])?'':Channel::where(['id'=>$customer['channel_id']])->value($nameLang);
|
||||
// $customer['last_follow'] = $last_follow;
|
||||
|
||||
if ($tag) {
|
||||
foreach ($customer['tags'] as &$tag) {
|
||||
$tag['names'] = unserialize($tag['names']);
|
||||
$tag['name'] = $tag['names'][$language];
|
||||
}
|
||||
}
|
||||
|
||||
return $customer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户的标签
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
return $this->belongsToMany(Tag::class, 'customer_tag', 'customer_id', 'tag_id')
|
||||
->withTimestamps(); // 如果需要记录关联时间
|
||||
}
|
||||
|
||||
|
||||
// 定义与 变更历史 的一对多关系
|
||||
public function his()
|
||||
{
|
||||
return $this->hasMany(CustomerHis::class, 'customer_id', 'id');
|
||||
}
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
use app\crm\utils\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CustomerHis extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'customer_his';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
/**
|
||||
* 重新格式化时间
|
||||
* @param DateTimeInterface $date
|
||||
* @return string
|
||||
*/
|
||||
protected function serializeDate(DateTimeInterface $date): string
|
||||
{
|
||||
return $date->format(Carbon::parse($date)->toDateTimeString());
|
||||
}
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function customer()
|
||||
{
|
||||
return $this->belongsTo(Customer::class, 'customer_id', 'id');
|
||||
}
|
||||
|
||||
// 禁用 updated_at 的自动更新
|
||||
public function setUpdatedAt($value)
|
||||
{
|
||||
return $this; // 不做任何操作
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
use app\crm\utils\Util;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CustomerTag extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'customer_tag';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id', 'created_at'];
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
use app\service\OssService;
|
||||
use app\crm\utils\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Follow extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'follow';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'follow_time'];
|
||||
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'follow_time' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'updated_at' => 'timestamp', // 指定序列化格式
|
||||
// 'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
public static function getFollow($follow,$domain = 'https://vehicle-album.oss-cn-beijing.aliyuncs.com')
|
||||
{
|
||||
$follow['type_txt'] = Constants::FOLLOW[$follow['type']];
|
||||
$follow['firstFollowtime'] = $follow['follow_time'];
|
||||
$ossservice = new OssService();
|
||||
$oss_picture = $ossservice->generatePrivateUrl($follow['picture'],86400);
|
||||
$follow['oss_picture'] = $oss_picture;
|
||||
// $follow = Util::formatDate($follow);
|
||||
return $follow;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Tag extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'tag';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function group()
|
||||
{
|
||||
return $this->belongsTo(TagGroup::class, 'group_id', 'id');
|
||||
}
|
||||
|
||||
public function customers()
|
||||
{
|
||||
return $this->belongsToMany(Customer::class, 'customer_tag', 'tag_id', 'customer_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\model;
|
||||
|
||||
|
||||
use app\crm\utils\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class TagGroup extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'tag_group';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
// 定义与 Tag 的一对多关系
|
||||
public function tags()
|
||||
{
|
||||
return $this->hasMany(Tag::class, 'group_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\service;
|
||||
|
||||
use app\crm\model\Customer;
|
||||
|
||||
class CustomerService
|
||||
{
|
||||
public function list($params)
|
||||
{
|
||||
// $page = $request->input('page', 1);
|
||||
// $perPage = $request->input('per_page', 10);
|
||||
$perPage = $params['size'] ?? 10;
|
||||
$page = $params['current'] ?? 1;
|
||||
$where = [];
|
||||
$user_id =$params['user_id'];
|
||||
if(empty($user_id) || $user_id == 0){
|
||||
$where[] = ['user_id', '=', $user_id];
|
||||
}
|
||||
$user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page);
|
||||
$user = $user->toArray();
|
||||
foreach ($user['data'] as &$item) {
|
||||
unset($item['password']);
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\service;
|
||||
|
||||
use app\crm\model\Follow;
|
||||
use app\crm\utils\Util;
|
||||
|
||||
class FollowService
|
||||
{
|
||||
|
||||
public function list($param)
|
||||
{
|
||||
|
||||
|
||||
// $page = $request->input('page', 1);
|
||||
// $perPage = $request->input('per_page', 10);
|
||||
|
||||
//客户id
|
||||
$customer_id =$param['customer_id'];
|
||||
|
||||
$where = [];
|
||||
$where['customer_id'] = $customer_id;
|
||||
|
||||
//用户角色
|
||||
$userId = $request->user['id'];
|
||||
if(Util::isEmpty($userId)){
|
||||
return $this->error(trans('user_none'));
|
||||
}
|
||||
if($request->user['role']!=1){
|
||||
$where['user_id'] = $userId;
|
||||
}
|
||||
|
||||
//跟进id
|
||||
$id = Util::getParam($request,'id');
|
||||
if(!Util::isEmpty($id)){
|
||||
$where['id'] = $id;
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
$data = Follow::where($where)
|
||||
->orderBy('id', 'desc')->get();
|
||||
// ->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
|
||||
// $host = $request->host();
|
||||
$url = 'http:'.$request->url();
|
||||
foreach ($data as &$value){
|
||||
$value = Follow::getFollow($value);
|
||||
}
|
||||
|
||||
return $this->success($data,trans('success'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\utils;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* 参数是否为空
|
||||
*/
|
||||
public static function isEmpty($param)
|
||||
{
|
||||
if(!empty($param) || $param == 0){
|
||||
$result = false;
|
||||
}else{
|
||||
$result = true;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数是否为空
|
||||
*/
|
||||
public static function getParam(Request $request,$param,$default='')
|
||||
{
|
||||
$param = $request->input($param,$default);
|
||||
if(empty($param) && $default!==''){
|
||||
$param = $default;
|
||||
}
|
||||
return $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
public static function fail($data = [],$message = '', $code = -1)
|
||||
{
|
||||
$result = [
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
public static function success($data = [],$message = '', $code = 0)
|
||||
{
|
||||
$result = [
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询返回
|
||||
*/
|
||||
public static function page($data,$message = '', $code = 0)
|
||||
{
|
||||
$result = [
|
||||
'code' => $code,
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
$result['data'] = [
|
||||
'list' => $data->items(), // 当前页数据
|
||||
'total' => $data->total(), // 总记录数
|
||||
'current_page' => $data->currentPage(),
|
||||
'per_page' => $data->perPage(),
|
||||
'last_page' => $data->lastPage()
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期格式转化
|
||||
*/
|
||||
public static function timeTotDate($time = 0, $format = 'Y-m-d H:i:s')
|
||||
{
|
||||
if (empty($time)) {
|
||||
return '';
|
||||
}
|
||||
return date($format, $time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化创建时间
|
||||
*/
|
||||
public static function formatDate($value,$key = ['created_at','updated_at'])
|
||||
{
|
||||
foreach ($key as $k){
|
||||
$value[$k]= self::timeTotDate($value[$k]);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化创建时间
|
||||
*/
|
||||
public static function language($language,$en,$zh_CN,$ru)
|
||||
{
|
||||
if ($language == 'zh_CN'){
|
||||
return $zh_CN;
|
||||
}elseif ($language == 'ru'){
|
||||
return $ru;
|
||||
}
|
||||
return $en;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace app\crm\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class FollowValidate extends Validate
|
||||
{
|
||||
|
||||
protected $rule = [
|
||||
'customer_id' => 'require',
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
'customer_id.require' => '用户id不能为空',
|
||||
];
|
||||
|
||||
protected $scene = [
|
||||
'upwd_list' => ['customer_id'],
|
||||
];
|
||||
}
|
||||
@@ -34,4 +34,104 @@ class Constants
|
||||
self::TICKET_STATUS['REJECTED'] => 'Закрыть',
|
||||
];
|
||||
|
||||
//客户分级 USTOMER_GRADE
|
||||
|
||||
public const GRADE = [
|
||||
'INITIAL' => 0, // 初步接触
|
||||
'COMMUNICATE' => 1, // 需求沟通
|
||||
'PLAN' => 2, // 方案推进
|
||||
'DEAL' => 3, // 成交阶段
|
||||
'SALES' => 4, // 售后阶段
|
||||
'LOSS' => 5, // 停滞或流失
|
||||
];
|
||||
|
||||
public const GRADE_ZH = [
|
||||
self::GRADE['INITIAL'] => '初步接触',
|
||||
self::GRADE['COMMUNICATE'] => '需求沟通',
|
||||
self::GRADE['PLAN'] => '方案推进',
|
||||
self::GRADE['DEAL'] => '成交阶段',
|
||||
self::GRADE['SALES'] => '售后阶段',
|
||||
self::GRADE['LOSS'] => '停滞或流失',
|
||||
];
|
||||
public const GRADE_EN = [
|
||||
self::GRADE['INITIAL'] => 'Initial contact',
|
||||
self::GRADE['COMMUNICATE'] => 'Demand Chat',
|
||||
self::GRADE['PLAN'] => 'promotion of the plan',
|
||||
self::GRADE['DEAL'] => 'Transaction Stage',
|
||||
self::GRADE['SALES'] => 'After Sales',
|
||||
self::GRADE['LOSS'] => 'Stagnation or loss',
|
||||
];
|
||||
public const GRADE_RU = [
|
||||
self::GRADE['INITIAL'] => 'Первоначальные контакты',
|
||||
self::GRADE['COMMUNICATE'] => 'Потребности в общении',
|
||||
self::GRADE['PLAN'] => 'Продвижение программы',
|
||||
self::GRADE['DEAL'] => 'Этап сделки',
|
||||
self::GRADE['SALES'] => 'Послепродажный этап',
|
||||
self::GRADE['LOSS'] => 'Застой или потеря',
|
||||
];
|
||||
|
||||
//客户重要性
|
||||
public const CUSTOMER_MAGNITUDE_INITIAL = 0; // 金牌商机
|
||||
public const CUSTOMER_MAGNITUDE_COMMUNICATE = 1; // 银牌商机
|
||||
public const CUSTOMER_MAGNITUDE_PLAN = 2; // 铜牌商机
|
||||
|
||||
public const MAGNITUDE = [
|
||||
self::CUSTOMER_MAGNITUDE_INITIAL => '金牌商机',
|
||||
self::CUSTOMER_MAGNITUDE_COMMUNICATE => '银牌商机',
|
||||
self::CUSTOMER_MAGNITUDE_PLAN => '铜牌商机',
|
||||
];
|
||||
public const MAGNITUDE_EN = [
|
||||
self::CUSTOMER_MAGNITUDE_INITIAL => 'Gold Medal',
|
||||
self::CUSTOMER_MAGNITUDE_COMMUNICATE => 'Silver Medal',
|
||||
self::CUSTOMER_MAGNITUDE_PLAN => 'Bronze Medal',
|
||||
];
|
||||
|
||||
public const MAGNITUDE_RU = [
|
||||
self::CUSTOMER_MAGNITUDE_INITIAL => 'Золотой бизнес',
|
||||
self::CUSTOMER_MAGNITUDE_COMMUNICATE => 'Серебряный бизнес',
|
||||
self::CUSTOMER_MAGNITUDE_PLAN => 'Бронзовый бизнес.',
|
||||
];
|
||||
|
||||
|
||||
//跟进类型
|
||||
public const CUSTOMER_FOLLOW_VISIT = 0; // 线下拜访
|
||||
public const CUSTOMER_FOLLOW_UP = 1; // 线上跟进
|
||||
|
||||
public const FOLLOW = [
|
||||
self::CUSTOMER_FOLLOW_VISIT => '线下拜访',
|
||||
self::CUSTOMER_FOLLOW_UP => '线上跟进',
|
||||
];
|
||||
public const FOLLOW_EN = [
|
||||
self::CUSTOMER_FOLLOW_VISIT => 'Visit',
|
||||
self::CUSTOMER_FOLLOW_UP => 'On line',
|
||||
];
|
||||
|
||||
//跟进类型
|
||||
public const CUSTOMER_SEX_UNKNOWN = 0; // 未知
|
||||
public const CUSTOMER_SEX_MAN = 1; // 男
|
||||
public const CUSTOMER_SEX_WOMAN = 2; // 女
|
||||
|
||||
public const SEX = [
|
||||
self::CUSTOMER_SEX_UNKNOWN => '未知',
|
||||
self::CUSTOMER_SEX_MAN => '男',
|
||||
self::CUSTOMER_SEX_WOMAN => '女',
|
||||
];
|
||||
public const SEX_EN = [
|
||||
self::CUSTOMER_SEX_UNKNOWN => 'unknown',
|
||||
self::CUSTOMER_SEX_MAN => 'man',
|
||||
self::CUSTOMER_SEX_WOMAN => 'woman',
|
||||
];
|
||||
|
||||
public const SEX_RU = [
|
||||
self::CUSTOMER_SEX_UNKNOWN => 'неизвестный',
|
||||
self::CUSTOMER_SEX_MAN => 'мужской',
|
||||
self::CUSTOMER_SEX_WOMAN => 'женский',
|
||||
];
|
||||
|
||||
public const SIGN = [
|
||||
['id' => 'xinyouhe', 'name' => '新友合'],
|
||||
['id' => 'mbaf', 'name' => 'MAGIC BRIDGE AUTO FZE']
|
||||
];
|
||||
|
||||
public const LANGUAGE = ['en', 'zh_CN','ru'];
|
||||
}
|
||||
Reference in New Issue
Block a user