Merge branch 'develop' into feature/mzl_dev
This commit is contained in:
@@ -35,6 +35,9 @@ class UserService
|
||||
/** 更新 */
|
||||
public function serviceUpdateUser(Request $request, array $data = [])
|
||||
{
|
||||
if(isset($data['report_to']) && empty($data['report_to'])){
|
||||
$data['report_to'] = 0;
|
||||
}
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
$config = $this->buildQueryConfig($request, 'update');
|
||||
$updated = $this->logicUpdateBy($config, $data);
|
||||
@@ -44,6 +47,9 @@ class UserService
|
||||
/** 更新 */
|
||||
public function serviceUpdate(Request $request, array $data = [])
|
||||
{
|
||||
if(isset($data['report_to']) && empty($data['report_to'])){
|
||||
$data['report_to'] = 0;
|
||||
}
|
||||
unset($data['roles']);
|
||||
unset($data['corp_name']);
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
@@ -75,6 +81,9 @@ class UserService
|
||||
$k = '%' . $p['keyword'] . '%';
|
||||
$config['where']['name'] = ['like', $k];
|
||||
}
|
||||
if (isset($p['status']) && $p['status']) {
|
||||
$config['where']['status'] = $p['status'];
|
||||
}
|
||||
if (isset($p['user_id']) && $p['user_id']) {
|
||||
$config['where']['user_id'] = $p['user_id'];
|
||||
}
|
||||
|
||||
@@ -87,13 +87,21 @@ class AuthLogic
|
||||
try {
|
||||
$phone = $this->sanitizePhone($feishuUserInfo['mobile'] ?? '');
|
||||
$email = $feishuUserInfo['enterprise_email'];
|
||||
$user = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
->where(function($query) use ($phone, $email) {
|
||||
$query->where('phone', $phone)
|
||||
->orWhere('email', $email);
|
||||
})
|
||||
->first();
|
||||
|
||||
// $user = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
// ->where(function($query) use ($phone, $email) {
|
||||
// $query->where('phone', $phone)
|
||||
// ->orWhere('email', $email);
|
||||
// })
|
||||
// ->first();
|
||||
$userByPhone = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
->where('phone', $phone)
|
||||
->where('phone', '!=', '')
|
||||
->first();
|
||||
$userByEmail = User::where('corp_id', $feishuUserInfo['corp_id'])
|
||||
->where('email', $email)
|
||||
->where('email', '!=', '')
|
||||
->first();
|
||||
$user = $userByPhone ?: $userByEmail;
|
||||
if (!$user) {
|
||||
// 获取编号
|
||||
$userSn = $this->getAvailableUserSn();
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class CustomerAudit extends Model
|
||||
{
|
||||
/**
|
||||
* The connection name for the model.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $connection = 'mysql';
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'crm_customer_audit';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* 允许自动填充模型字段
|
||||
*/
|
||||
protected $fillable = ['id', 'customer_id', 'remark', 'img', 'audit', 'report_user_id', 'audit_user_id', 'created_at', 'updated_at'];
|
||||
|
||||
/**
|
||||
* 不允许自动填充模型字段
|
||||
*/
|
||||
protected $guarded = [];
|
||||
}
|
||||
@@ -80,6 +80,7 @@
|
||||
<li>工单编号:{{code}}</li>
|
||||
<li>工单分类:{{category}}</li>
|
||||
<li>问题描述:{{content}}</li>
|
||||
{{reply}}
|
||||
</ul>
|
||||
|
||||
<p>请点击下方按钮立即查看详情:</p>
|
||||
|
||||
@@ -50,6 +50,7 @@ class CustomerController extends BaseController
|
||||
: null);
|
||||
foreach ($data['records'] as &$item) {
|
||||
$item = $this->service->getCustomer($item);
|
||||
$item = Util::formatDate($item,['created_at','updated_at']);
|
||||
}
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
@@ -162,7 +163,7 @@ class CustomerController extends BaseController
|
||||
$perPage = $request->input('size', 10);
|
||||
$where = [
|
||||
['user_id', '=', $userId],
|
||||
['corp_abbr', '=', $request->basic_data['corp_abbr']],
|
||||
// ['corp_abbr', '=', $request->basic_data['corp_abbr']],
|
||||
['follow_next', '<>', 0],
|
||||
];
|
||||
|
||||
@@ -239,6 +240,9 @@ class CustomerController extends BaseController
|
||||
if (Util::isEmpty($param['id'])) {
|
||||
return $this->error(trans('id_empty'));
|
||||
}
|
||||
if (empty($param['remark']) && empty($param['img'])) {
|
||||
return $this->error('举报理由不能为空');
|
||||
}
|
||||
|
||||
$param['user_id'] = $request->user->uid;
|
||||
$param['corp_abbr'] = $request->basic_data['corp_abbr'];
|
||||
@@ -326,6 +330,7 @@ class CustomerController extends BaseController
|
||||
'address' => Util::getParam($request, 'address', ''),
|
||||
'sex' => Util::getParam($request, 'sex', 0),
|
||||
'obtain' => time(),
|
||||
'company' => Util::getParam($request, 'company', 0),
|
||||
];
|
||||
|
||||
if (Util::isEmpty($id)) {
|
||||
@@ -383,7 +388,7 @@ class CustomerController extends BaseController
|
||||
public function delete(Request $request)
|
||||
{
|
||||
$id = Util::getParam($request, 'id');
|
||||
$force = Util::getParam($request, 'force','');
|
||||
$scene = Util::getParam($request, 'scene','');
|
||||
|
||||
$userId = $request->user->uid;
|
||||
$where = [
|
||||
@@ -396,10 +401,11 @@ class CustomerController extends BaseController
|
||||
}
|
||||
try {
|
||||
Db::beginTransaction();
|
||||
if ($force == 'force') {
|
||||
//强制删除
|
||||
$res = $customer->forceDelete();
|
||||
} else {
|
||||
if ($scene == 'force') {
|
||||
//status=5:业务员自己删除
|
||||
$customer->status = 5;
|
||||
$res = $customer->save();
|
||||
}else{
|
||||
$customer->user_id = 0;
|
||||
$customer->save();
|
||||
|
||||
@@ -409,10 +415,10 @@ class CustomerController extends BaseController
|
||||
'user_his' => $userId,
|
||||
'user_id' => 0,
|
||||
]);
|
||||
|
||||
//软删除
|
||||
$res = $customer->delete();
|
||||
}
|
||||
|
||||
//软删除
|
||||
$res = $customer->delete();
|
||||
Db::commit();
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
|
||||
@@ -36,15 +36,22 @@ class Follow extends Model
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
public $timestamps = false;
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'follow_time'];
|
||||
/**
|
||||
* 在保存时手动设置时间戳
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
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', // 指定序列化格式
|
||||
];
|
||||
static::creating(function ($model) {
|
||||
$model->created_at = time();
|
||||
$model->updated_at = time();
|
||||
});
|
||||
|
||||
static::updating(function ($model) {
|
||||
$model->updated_at = time();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,23 @@
|
||||
namespace app\crm\service;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\common\model\CustomerAudit;
|
||||
use app\common\model\User;
|
||||
use app\common\traits\crud\CrudServiceTrait;
|
||||
use app\crm\logic\CustomerLogic;
|
||||
use app\crm\model\Channel;
|
||||
use app\crm\model\Country;
|
||||
use app\crm\model\Customer;
|
||||
use app\crm\model\Tag;
|
||||
use app\crm\model\CustomerHis;
|
||||
use app\crm\model\Follow;
|
||||
use app\crm\utils\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Request;
|
||||
|
||||
/**
|
||||
* @method mixed complexQuery(array $params)
|
||||
*/
|
||||
class CustomerService
|
||||
{
|
||||
|
||||
@@ -36,6 +41,8 @@ class CustomerService
|
||||
$follow = $params['follow'] ?? '';
|
||||
$follow_last = $params['follow_last'] ?? '';
|
||||
$tagId = $params['tag_id'] ?? [];
|
||||
$sort = $params['sort'] ?? null;
|
||||
$sortId = $params['sort_id'] ?? null;
|
||||
$countryId = $params['country_id'] ?? '';
|
||||
$where = [];
|
||||
$user_id =$params['user_id'];
|
||||
@@ -71,7 +78,7 @@ class CustomerService
|
||||
$where[] = ['follow_last', '>', strtotime('-7 day')];
|
||||
}
|
||||
|
||||
$query = Customer::where($where);
|
||||
$query = Customer::select('crm_customer.*')->where($where);
|
||||
|
||||
if(!empty($tagId)){
|
||||
//查询有$tagId 里任意一个标签的客户
|
||||
@@ -114,7 +121,33 @@ class CustomerService
|
||||
$query->withTrashed();
|
||||
}
|
||||
|
||||
$customer = $query->orderBy('id','desc')->paginate($perPage, ['*'], 'page', $page);
|
||||
if ($sort == 'tag_group') {
|
||||
// 排序:按关联的 crm_tag.sort 最小值升序,其次按客户ID倒序
|
||||
$minSortSub = Tag::selectRaw('MIN(crm_tag.sort) AS min_sort, crm_customer_tag.customer_id')
|
||||
->join('crm_customer_tag', 'crm_customer_tag.tag_id', '=', 'crm_tag.id')
|
||||
->whereNull('crm_tag.deleted_at')
|
||||
->when(!empty($sortId), function ($q) use ($sortId) {
|
||||
$q->where('crm_tag.group_id', $sortId);
|
||||
})
|
||||
->groupBy('crm_customer_tag.customer_id');
|
||||
|
||||
$query->leftJoinSub($minSortSub, 'tag_min', function ($join) {
|
||||
$join->on('crm_customer.id', '=', 'tag_min.customer_id');
|
||||
});
|
||||
|
||||
$query = $query->orderByRaw('tag_min.min_sort IS NULL')
|
||||
->orderBy('tag_min.min_sort', 'asc')
|
||||
->orderBy('crm_customer.id', 'desc');
|
||||
}elseif ($sort == 'follow_last') {
|
||||
$query = $query->orderBy('crm_customer.follow_last', 'desc');
|
||||
}elseif ($sort == 'follow_next') {
|
||||
$query = $query->orderByRaw('crm_customer.follow_next IS NULL, crm_customer.follow_next ASC');
|
||||
}elseif ($sort == 'id' || empty($sort)) {
|
||||
$query = $query->orderBy('crm_customer.id', 'desc');
|
||||
}
|
||||
|
||||
$customer = $query->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
foreach ($customer as &$item) {
|
||||
$item = $this->getCustomer($item);
|
||||
if($seas == 'seas'){
|
||||
@@ -195,6 +228,14 @@ class CustomerService
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomerAudit::create([
|
||||
'customer_id' => $id,
|
||||
'report_user_id' => $userId,
|
||||
'remark' => $params['remark'],
|
||||
'status' => 1,
|
||||
'img' => implode(',', $params['img']),
|
||||
]);
|
||||
|
||||
CustomerHis::create([
|
||||
'customer_id' => $id,
|
||||
'user_his' => $userId,
|
||||
@@ -247,7 +288,7 @@ class CustomerService
|
||||
// $customer['created_at'] = Util::timeTotDate($customer['created_at']);
|
||||
// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']);
|
||||
|
||||
$customer = Util::formatDate($customer,['follow_last']);
|
||||
$customer = Util::formatDate($customer,['follow_next','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);
|
||||
@@ -272,7 +313,7 @@ class CustomerService
|
||||
public function detail($params)
|
||||
{
|
||||
$id =$params['id'];
|
||||
$customer = Customer::with('tags')->select('id', 'user_id', 'grade', 'channel_id', 'car_type_id', 'country_id', 'magnitude', 'email', 'phone', 'WhatsApp', 'contacts', 'describe', 'address', 'lat', 'lng', 'follow_next', 'follow_remark', 'sex')
|
||||
$customer = Customer::with('tags')->select('id', 'user_id', 'grade', 'channel_id', 'car_type_id', 'country_id', 'magnitude', 'email', 'phone', 'WhatsApp', 'contacts', 'describe', 'address', 'lat', 'lng', 'follow_next', 'follow_remark', 'sex', 'company')
|
||||
->where('id', $id)
|
||||
->first();
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ class FollowService
|
||||
$oss_picture = $ossservice->generatePrivateUrl($follow['picture'], 86400);
|
||||
}
|
||||
$follow['picture_full'] = $oss_picture;
|
||||
|
||||
$follow = Util::formatDate($follow,['created_at','updated_at','follow_time']);
|
||||
$follow['follow_time'] = empty($follow['follow_time'])?'':$follow['follow_time'];
|
||||
// $follow = Util::formatDate($follow);
|
||||
return $follow;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,13 @@ class Util
|
||||
public static function formatDate($value,$key = ['created_at','updated_at'])
|
||||
{
|
||||
foreach ($key as $k){
|
||||
$value[$k]= self::timeTotDate($value[$k]);
|
||||
// 如果是整数,可能是 UNIX 时间戳
|
||||
if (is_numeric($value[$k]) && $value[$k] > 0) {
|
||||
// 检查是否是合理的时间戳范围(1970-2100年)
|
||||
if ($value[$k] >= 0 && $value[$k] <= 4102444800) {
|
||||
$value[$k]= self::timeTotDate($value[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace app\crmAdmin\controller;
|
||||
|
||||
use app\common\model\Corp;
|
||||
use app\crm\model\Customer;
|
||||
use app\crm\utils\Util;
|
||||
use app\crmAdmin\service\CustomerService;
|
||||
use support\Request;
|
||||
|
||||
@@ -85,7 +86,7 @@ class CustomerController extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户列表
|
||||
* 审核客户
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
@@ -147,17 +148,19 @@ class CustomerController extends BaseController
|
||||
return $this->error('customer_id'.trans('not_null'));
|
||||
}
|
||||
|
||||
$where = [
|
||||
'id' => $param['customer_id'],
|
||||
];
|
||||
$customer = Customer::where($where)->withTrashed()->first();
|
||||
if(empty($customer)){
|
||||
$customer_id = explode(',', $param['customer_id']);
|
||||
$query = Customer::whereIn('id',$customer_id)->withTrashed();
|
||||
if(!$query->exists()){
|
||||
return $this->error( trans('fail'));
|
||||
}
|
||||
//软删除
|
||||
$customer->status = 3;
|
||||
$res = $customer->save();
|
||||
$customer->delete();
|
||||
$scene = $param['scene'] ?? '';
|
||||
if ($scene === 'list') { //管理端客户列表移除
|
||||
$res = $query->update(['status' => 4, 'deleted_at' => time()]);
|
||||
} elseif ($scene === 'force') { //强删除
|
||||
$res = $query->forceDelete();
|
||||
} else { //公海软删除
|
||||
$res = $query->update(['status' => 3, 'deleted_at' => time()]);
|
||||
}
|
||||
|
||||
return $this->success($res);
|
||||
} catch (\Throwable $th) {
|
||||
@@ -165,6 +168,34 @@ class CustomerController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 客户恢复
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function restore(Request $request)
|
||||
{
|
||||
try {
|
||||
$id = $request->input('id', '');
|
||||
if (Util::isEmpty($id)) {
|
||||
return $this->error(trans('id_empty'));
|
||||
}
|
||||
$ids = explode(',', $id);
|
||||
$query = Customer::withTrashed()->whereIn('id', $ids);
|
||||
if (!$query->exists()) {
|
||||
return $this->error(trans('fail'));
|
||||
}
|
||||
// 恢复软删除(清空 deleted_at)
|
||||
$query->restore();
|
||||
// 恢复为在库状态,放入公海
|
||||
$res = Customer::whereIn('id', $ids)->update(['status' => 1, 'user_id' => 0]);
|
||||
return $this->success($res, trans('success'));
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户详情
|
||||
* @param Request $request
|
||||
@@ -207,4 +238,28 @@ class CustomerController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 离职员工客户分配
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function allocation(Request $request)
|
||||
{
|
||||
try {
|
||||
$param = $request->all();
|
||||
if (empty($param['corp_id'])) {
|
||||
return $this->error('corp_id'.trans('not_null'));
|
||||
}
|
||||
if (empty($param['user_id'])) {
|
||||
return $this->error('user_id'.trans('not_null'));
|
||||
}
|
||||
|
||||
$result = (new CustomerService())->allocation($param);
|
||||
|
||||
return $this->success($result,'成功分配'.$result['userCount'].'位离职用户的'.$result['customerCount'].'位客户');
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ class CustomerLogic
|
||||
$customer->restore();
|
||||
}
|
||||
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace app\crmAdmin\service;
|
||||
|
||||
use app\common\model\CustomerAudit;
|
||||
use app\common\model\InquiryLog;
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
@@ -20,6 +21,8 @@ use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Border;
|
||||
use PhpOffice\PhpSpreadsheet\Style\Fill;
|
||||
use support\Db;
|
||||
use support\exception\BusinessException;
|
||||
use support\Log;
|
||||
|
||||
class CustomerService
|
||||
{
|
||||
@@ -48,12 +51,14 @@ class CustomerService
|
||||
$follow_last = $params['follow_last'] ?? '';
|
||||
$tagId = $params['tag_id'] ?? [];
|
||||
$user_id = $params['user_id'] ?? '';
|
||||
$seas = $params['seas'] ?? '';
|
||||
$seas = $params['seas'] ?? ''; //recyclea:管理端回收站,audit:待审核列表,seas:公海
|
||||
$scene = $params['scene'] ?? '';
|
||||
$where = [];
|
||||
|
||||
if ($scene == 'audit') {
|
||||
$where[] = ['status', '=', 2];
|
||||
} elseif ($scene == 'recyclea') {
|
||||
$where[] = ['status', '>', 2];
|
||||
} else {
|
||||
$where[] = ['status', '=', 1];
|
||||
}
|
||||
@@ -118,8 +123,8 @@ class CustomerService
|
||||
if ($recycle == 'recycle' || $scene == 'recycle' || $scene == 'audit') {
|
||||
$query->onlyTrashed();
|
||||
}
|
||||
if ($seas == 'seas' || $scene == 'seas') {
|
||||
$query->withTrashed();
|
||||
if ($seas == 'seas' || $scene == 'recyclea') {
|
||||
$query = $query->withTrashed();
|
||||
}
|
||||
|
||||
if (!$export) {
|
||||
@@ -132,13 +137,31 @@ class CustomerService
|
||||
foreach ($customer as &$item) {
|
||||
$item = $this->getCustomer($item);
|
||||
$item['desc_collect'] = $item['desc_collect'] ?? '';
|
||||
$item['follow_next'] = empty($item['follow_next'])?'':date('Y-m-d H:i:s', $item['follow_next']);
|
||||
if ($seas == 'seas' || $scene == 'seas') {
|
||||
$item['seas_time'] = time() - (empty($item['deleted_at'])?strtotime($item['updated_at']):strtotime($item['deleted_at']));
|
||||
}
|
||||
if ($scene == 'audit') { //审核时查询举报人姓名
|
||||
$customerHis = CustomerHis::where('customer_id', $item->id)->orderBy('id', 'desc')->first(['user_his']);
|
||||
$item['user_name'] = empty($customerHis['user_his']) ? '' : User::where('id',$customerHis['user_his'])->value('name');
|
||||
$audit = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first();
|
||||
if (!empty($audit)&&!empty($audit['img'])) {
|
||||
$audit = $audit?$audit->toArray():'';
|
||||
$audit['img'] = explode(',', $audit['img']);
|
||||
|
||||
$ossservice = new OssService();
|
||||
foreach ($audit['img'] as $k => $img) {
|
||||
$audit['img'][$k] = $ossservice->generatePrivateUrl($img);
|
||||
}
|
||||
}
|
||||
$item['audit'] = $audit;
|
||||
}
|
||||
if ($scene == 'recyclea' && $item['status'] == 3) { //回收站删除来源
|
||||
$item['del_source'] = '公海';
|
||||
}elseif ($scene == 'recyclea' && $item['status'] == 4) {
|
||||
$item['del_source'] = '管理端';
|
||||
}elseif ($scene == 'recyclea' && $item['status'] == 5) {
|
||||
$source = (!empty($item['user_id'])) ? (':' . User::where('id',$item['user_id'])->value('name')) : '';
|
||||
$item['del_source'] = '业务员' . $source;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,9 +310,18 @@ class CustomerService
|
||||
$id = $params['id'];
|
||||
|
||||
$logic = new CustomerLogic();
|
||||
$audit = CustomerAudit::where('customer_id', $id)->orderBy('id', 'desc')->first();
|
||||
if ($params['scene'] == 'delete') {
|
||||
if(!empty($audit)){
|
||||
$audit->status = 3;
|
||||
$audit->save();
|
||||
}
|
||||
return $logic->forceDelete($params['id']);
|
||||
} else {
|
||||
if(!empty($audit)){
|
||||
$audit->status = 2;
|
||||
$audit->save();
|
||||
}
|
||||
return $logic->status($params['id'], 1);
|
||||
}
|
||||
}
|
||||
@@ -404,7 +436,7 @@ class CustomerService
|
||||
// $customer['created_at'] = Util::timeTotDate($customer['created_at']);
|
||||
// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']);
|
||||
|
||||
$customer = Util::formatDate($customer, ['follow_last']);
|
||||
$customer = Util::formatDate($customer, ['follow_next','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);
|
||||
@@ -447,9 +479,69 @@ class CustomerService
|
||||
|
||||
$ossservice = new OssService();
|
||||
foreach ($follow as $item) {
|
||||
$item = Util::formatDate($item,['created_at','updated_at','follow_time']);
|
||||
$item['follow_time'] = empty($item['follow_time'])?'':$item['follow_time'];
|
||||
$item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture);
|
||||
}
|
||||
|
||||
return $follow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 离职员工客户分配
|
||||
* @param $params
|
||||
* @return string[]
|
||||
*/
|
||||
public function allocation($params)
|
||||
{
|
||||
$corpId = $params['corp_id'];
|
||||
$userId = explode(',', $params['user_id']);
|
||||
|
||||
log::info('开始分配离职员工客户,corp_id:'.$corpId.' 被分配员工'. implode(',', $userId));
|
||||
|
||||
//查询离职客户
|
||||
$userResign = User::where('status', 2)
|
||||
->where('corp_id', $corpId)
|
||||
->get(['id','name']);
|
||||
|
||||
$resignUerIds = [];
|
||||
$userNames = [];
|
||||
foreach ($userResign as $row) {
|
||||
$resignUerIds[] = (int)$row->id;
|
||||
$userNames[] = $row->name;
|
||||
}
|
||||
if (empty($userResign)) {
|
||||
log::info('未匹配到离职用户');
|
||||
throw new BusinessException('未匹配到离职用户', 500);
|
||||
}
|
||||
log::info('匹配到离职用户数:' . count($resignUerIds) .' '. implode(',',$userNames));
|
||||
|
||||
$customerCount = Customer::whereIn('user_id', $resignUerIds)
|
||||
->orderBy('id', 'asc')
|
||||
->count();
|
||||
|
||||
if ($customerCount === 0) {
|
||||
log::info('未找到离职员工相关的客户记录。');
|
||||
throw new BusinessException('未找到离职员工相关的客户记录', 500);
|
||||
}
|
||||
|
||||
// 初始化 UID 轮询器
|
||||
$uidRotator = new \app\common\utils\RedisUidRotator('allocation_customer_user');
|
||||
$uidRotator->setUids($userId, false);
|
||||
|
||||
Customer::whereIn('user_id',$resignUerIds)->chunk(500, function ($customers) use ($uidRotator){
|
||||
foreach ($customers as $customer) {
|
||||
// 获取下一个分配的UID
|
||||
$newUserId = $uidRotator->next();
|
||||
$customer->user_id = $newUserId;
|
||||
$customer->save();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return [
|
||||
'userCount' => count($resignUerIds),
|
||||
'customerCount' => $customerCount,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,24 @@ class ConversationController extends BaseController
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单邮件补发
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function sendEmail(Request $request)
|
||||
{
|
||||
try {
|
||||
$res = (new ConversationService())->sendEmail($request->all());
|
||||
return $res
|
||||
? $this->success($res)
|
||||
: $this->error();
|
||||
} catch (\Throwable $th) {
|
||||
return $this->error($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function edit(Request $request)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -23,6 +23,14 @@ class CategorieLogic
|
||||
return Categorie::with('translation')->where($where)->get();
|
||||
}
|
||||
|
||||
public function find($id)
|
||||
{
|
||||
return Categorie::with(['translation' => function ($query) {
|
||||
$query->where('locale', locale());
|
||||
}])->where('status', 1)
|
||||
->find($id);
|
||||
}
|
||||
|
||||
public function add(array $data)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -18,6 +18,7 @@ class ConversationLogic
|
||||
$current = $params['current'] ?? 1;
|
||||
return Conversation::where($where)->paginate($size, ['*'], 'page', $current);
|
||||
}
|
||||
|
||||
public function add(array $data)
|
||||
{
|
||||
try {
|
||||
@@ -43,4 +44,17 @@ class ConversationLogic
|
||||
throw new BusinessException('会话编辑失败,请稍后重试', 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工单最新一条记录
|
||||
* @param array $data
|
||||
* @return Conversation|\Illuminate\Database\Eloquent\Model|object|null
|
||||
*/
|
||||
public function firstByTicket(int $ticketId)
|
||||
{
|
||||
$conversation = Conversation::where('ticket_id',$ticketId)
|
||||
->orderBy('id','desc')
|
||||
->first();
|
||||
return $conversation;
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,7 @@ class Conversation extends Model
|
||||
protected $primaryKey = 'id';
|
||||
public $timestamps = true;
|
||||
protected $dateFormat = 'U';
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s',
|
||||
'created_at' => 'datetime:Y-m-d H:i:s',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'ticket_id',
|
||||
'user_id',
|
||||
|
||||
@@ -47,16 +47,34 @@ class Ticket extends Model
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
public $timestamps = false;
|
||||
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
protected $dates = ['created_at', 'updated_at'];
|
||||
/**
|
||||
* 在保存时手动设置时间戳
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
];
|
||||
static::creating(function ($model) {
|
||||
$model->created_at = time();
|
||||
$model->updated_at = time();
|
||||
});
|
||||
|
||||
static::updating(function ($model) {
|
||||
$model->updated_at = time();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定哪些字段自动转换为 Carbon 实例
|
||||
*/
|
||||
public function getDates()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected $fillable = [
|
||||
'code',
|
||||
|
||||
@@ -4,7 +4,10 @@ namespace app\ticket\service;
|
||||
|
||||
use app\common\model\User;
|
||||
use app\common\service\OssService;
|
||||
use app\ticket\logic\CategorieLogic;
|
||||
use app\ticket\logic\ConversationLogic;
|
||||
use app\ticket\logic\TicketLogic;
|
||||
use app\ticket\model\Conversation;
|
||||
use config\constants\Constants;
|
||||
use support\Db;
|
||||
use support\exception\BusinessException;
|
||||
@@ -32,6 +35,8 @@ class ConversationService
|
||||
$user = User::where('id', $value['user_id'])->first();
|
||||
$value['user_name'] = $user?->name;
|
||||
$value['user_avatar'] = $user?->avatar;
|
||||
$value['created_at'] = date('Y-m-d H:i:s', strtotime($value['created_at']));
|
||||
$value['updated_at'] = date('Y-m-d H:i:s', strtotime($value['updated_at']));
|
||||
$result[$key] = $value;
|
||||
}
|
||||
return $result;
|
||||
@@ -44,12 +49,96 @@ class ConversationService
|
||||
if (empty($data['content'])) {
|
||||
throw new BusinessException('消息内容不能为空');
|
||||
}
|
||||
|
||||
$conversation = (new ConversationLogic())->firstByTicket($data['ticket_id']);
|
||||
$ticket = (new TicketLogic())->find($data['ticket_id']);
|
||||
$categorie= (new CategorieLogic())->find($ticket['categorie_id']);
|
||||
$categorieName = isset($categorie['translation']) ? $categorie['translation']['name'] : '';
|
||||
|
||||
$notice = [
|
||||
'code' => $ticket['code'],
|
||||
'category' => $categorieName,
|
||||
'content' => $data['content'],
|
||||
'reply' => '',
|
||||
];
|
||||
//$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱
|
||||
//$emailDefault = 'support@hnxinyouhe.com'; //公共邮箱
|
||||
$emailDefault = env('TICKET_EMAIL_DEFAULT');
|
||||
if (empty($conversation)) {
|
||||
$email = $emailDefault;
|
||||
}else{
|
||||
$tiket = (new TicketLogic())->find($conversation['ticket_id']);
|
||||
if($data['user_id'] != $tiket['user_id']){
|
||||
$email = User::where('id',$tiket['user_id'])->value('email');
|
||||
}else{
|
||||
$conversationLast = Conversation::where('ticket_id', '=', $conversation['ticket_id'])
|
||||
->where('user_id', '!=', $data['user_id'])
|
||||
->orderBy('id', 'desc')
|
||||
->first();
|
||||
|
||||
$email = (!empty($conversationLast['user_id']))?User::where('id',$conversationLast['user_id'])->value('email',$emailDefault):$emailDefault;
|
||||
}
|
||||
$notice['content'] = $tiket['content'];
|
||||
|
||||
$status_fanyi = array_map(fn($v) => "{{{$v}}}", array_flip(Constants::TICKET_STATUS));
|
||||
$locale = locale();
|
||||
$ticket_status = $locale == 'zh'? Constants::TICKET_STATUS_ZH:Constants::TICKET_STATUS_EN;
|
||||
$content = str_replace($status_fanyi,$ticket_status,$data['content']);
|
||||
|
||||
$notice['reply'] = '<li>最新回复:' . $content . '</li>';
|
||||
}
|
||||
if(!empty($emailDefault)){
|
||||
\app\common\utils\email\MailSend::send($email, '【XYH】新的工单提醒', replaceTpl($notice, 'work_order'));
|
||||
}
|
||||
|
||||
unset($data['categorie_id']);
|
||||
unset($data['code']);
|
||||
|
||||
return (new ConversationLogic())->add($data);
|
||||
} catch (\Throwable $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function sendEmail(array $data)
|
||||
{
|
||||
$conversation = (new ConversationLogic())->firstByTicket($data['ticket_id']);
|
||||
$ticket = (new TicketLogic())->find($data['ticket_id']);
|
||||
$categorie= (new CategorieLogic())->find($ticket['categorie_id']);
|
||||
$categorieName = isset($categorie['translation']) ? $categorie['translation']['name'] : '';
|
||||
$notice = [
|
||||
'code' => $ticket['code'],
|
||||
'category' => $categorieName,
|
||||
'content' => $ticket['content'],
|
||||
'reply' => '',
|
||||
];
|
||||
//$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱
|
||||
//$emailDefault = 'support@hnxinyouhe.com'; //公共邮箱
|
||||
$emailDefault = env('ticket_email_default');
|
||||
if (empty($conversation)) {
|
||||
$email = $emailDefault;
|
||||
}else{
|
||||
$tiket = (new TicketLogic())->find($conversation['ticket_id']);
|
||||
|
||||
if($conversation['user_id'] != $tiket['user_id']){
|
||||
$email = User::where('id',$tiket['user_id'])->value('email');
|
||||
}else{
|
||||
$conversationLast = Conversation::where('ticket_id', '=', $conversation['ticket_id'])
|
||||
->where('user_id', '!=', $conversation['user_id'])
|
||||
->orderBy('id', 'desc')
|
||||
->first();
|
||||
$email = (!empty($conversationLast['user_id']))?User::where('id',$conversationLast['user_id'])->value('email',$emailDefault):$emailDefault;
|
||||
}
|
||||
|
||||
$notice['content'] = $tiket['content'];
|
||||
// $notice['reply'] = '<li>最新回复:' . $conversation['content'] . '</li>';
|
||||
$notice['reply'] = '<li>最新回复:' . '卡罗拉、极石01、比亚迪唐,宋Plus、丰田荣放、捷途T2、极氪7x、(阿联酋, 亚美尼亚, 阿塞拜疆, 白俄罗斯, 哥斯达黎加, 埃塞俄比亚, 格鲁吉亚, 加纳, 吉尔吉斯斯坦, 蒙古, 巴拉圭, 沙特阿拉伯, 塔吉克斯坦, 土库曼斯坦, 乌兹别克斯坦,委内瑞拉)起亚亦跑(阿尔及利亚),基本上每个车都推中亚中东南美非洲' . '</li>';
|
||||
}
|
||||
|
||||
\app\common\utils\email\MailSend::send($email, '【XYH】新的工单提醒', replaceTpl($notice, 'work_order'));
|
||||
return $email;
|
||||
}
|
||||
|
||||
public function edit(array $data)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -33,6 +33,8 @@ class TicketService
|
||||
$user = User::where('id', $v['user_id'])->first();
|
||||
$res[$k]['user_name'] = $user?->name;
|
||||
$res[$k]['user_avatar'] = $user?->avatar;
|
||||
$res[$k]['created_at'] = date('Y-m-d H:i:s', $v['created_at']);
|
||||
$res[$k]['updated_at'] = date('Y-m-d H:i:s', $v['updated_at']);
|
||||
}
|
||||
unset($v);
|
||||
unset($attachments);
|
||||
@@ -45,6 +47,7 @@ class TicketService
|
||||
try {
|
||||
$attachment = $data['attachment']??[];
|
||||
$logic = new TicketLogic();
|
||||
$data['code'] = $logic::generateSimpleTicketNo();
|
||||
$result = $logic->add($data);
|
||||
if(!empty($attachment)){
|
||||
(new AttachmentLogic())->adds($attachment, $result->id, $data['user_id']);
|
||||
@@ -53,6 +56,8 @@ class TicketService
|
||||
$cleanContent = trim(preg_replace('/\s+/', ' ', strip_tags($data['content'] ?? '')));
|
||||
$conversation = [
|
||||
'ticket_id' => $result->id,
|
||||
'categorie_id' => $data['categorie_id'],
|
||||
'code' => $data['code'],
|
||||
'content' => $cleanContent,
|
||||
'user_id' => $data['user_id'],
|
||||
'attachment' => $data['attachment'],
|
||||
|
||||
@@ -176,8 +176,10 @@ Route::group('/admin', function () {
|
||||
Route::any('/transfer', [app\crmAdmin\controller\CustomerController::class, 'transfer']);
|
||||
Route::any('/detail', [app\crmAdmin\controller\CustomerController::class, 'detail']);
|
||||
Route::any('/delete', [app\crmAdmin\controller\CustomerController::class, 'delete']);
|
||||
Route::any('/restore', [app\crmAdmin\controller\CustomerController::class, 'restore']); //恢复客户
|
||||
Route::any('/cede', [app\crm\controller\CustomerController::class, 'cede']);
|
||||
Route::any('/follow', [app\crmAdmin\controller\CustomerController::class, 'follow']);
|
||||
Route::any('/allocation', [app\crmAdmin\controller\CustomerController::class, 'allocation']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -197,6 +199,7 @@ Route::group('/ticket', function () {
|
||||
|
||||
//工单沟通记录
|
||||
Route::any('/conversation/add', [app\ticket\controller\ConversationController::class, 'add']);
|
||||
Route::any('/conversation/sendEmail', [app\ticket\controller\ConversationController::class, 'sendEmail']);
|
||||
Route::any('/conversation/edit', [app\ticket\controller\ConversationController::class, 'edit']);
|
||||
Route::any('/conversation/list', [app\ticket\controller\ConversationController::class, 'index']);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user