diff --git a/app/admin/service/UserService.php b/app/admin/service/UserService.php index 4d23710..6675a89 100644 --- a/app/admin/service/UserService.php +++ b/app/admin/service/UserService.php @@ -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']; } diff --git a/app/common/logic/AuthLogic.php b/app/common/logic/AuthLogic.php index 9857df8..c79b1d1 100644 --- a/app/common/logic/AuthLogic.php +++ b/app/common/logic/AuthLogic.php @@ -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(); diff --git a/app/common/model/CustomerAudit.php b/app/common/model/CustomerAudit.php new file mode 100644 index 0000000..4e52267 --- /dev/null +++ b/app/common/model/CustomerAudit.php @@ -0,0 +1,49 @@ +工单编号:{{code}}
  • 工单分类:{{category}}
  • 问题描述:{{content}}
  • + {{reply}}

    请点击下方按钮立即查看详情:

    diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 3b6e8ec..e51b83f 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -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(); diff --git a/app/crm/model/Follow.php b/app/crm/model/Follow.php index 778b669..f57ef18 100644 --- a/app/crm/model/Follow.php +++ b/app/crm/model/Follow.php @@ -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(); + }); + } } \ No newline at end of file diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 0573972..a3559d5 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -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(); diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php index e8ce0f7..a433692 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -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; } diff --git a/app/crm/utils/Util.php b/app/crm/utils/Util.php index e6ac4d0..586ee45 100644 --- a/app/crm/utils/Util.php +++ b/app/crm/utils/Util.php @@ -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; } diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index a3dc0e2..c68bd18 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -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()); + } + } + } \ No newline at end of file diff --git a/app/crmAdmin/logic/CustomerLogic.php b/app/crmAdmin/logic/CustomerLogic.php index 83ba426..13efe9c 100644 --- a/app/crmAdmin/logic/CustomerLogic.php +++ b/app/crmAdmin/logic/CustomerLogic.php @@ -17,6 +17,7 @@ class CustomerLogic $customer->restore(); } + return $res; } diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 074f341..a7f2cea 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -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, + ]; + } } \ No newline at end of file diff --git a/app/ticket/controller/ConversationController.php b/app/ticket/controller/ConversationController.php index fcc8ef6..6b90750 100644 --- a/app/ticket/controller/ConversationController.php +++ b/app/ticket/controller/ConversationController.php @@ -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 { diff --git a/app/ticket/logic/CategorieLogic.php b/app/ticket/logic/CategorieLogic.php index c11bd64..7eefaed 100644 --- a/app/ticket/logic/CategorieLogic.php +++ b/app/ticket/logic/CategorieLogic.php @@ -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 { diff --git a/app/ticket/logic/ConversationLogic.php b/app/ticket/logic/ConversationLogic.php index d47a709..53a5a18 100644 --- a/app/ticket/logic/ConversationLogic.php +++ b/app/ticket/logic/ConversationLogic.php @@ -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; + } } \ No newline at end of file diff --git a/app/ticket/model/Conversation.php b/app/ticket/model/Conversation.php index f275f2b..641ff35 100644 --- a/app/ticket/model/Conversation.php +++ b/app/ticket/model/Conversation.php @@ -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', diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php index cf71b2a..d1bbe9e 100644 --- a/app/ticket/model/Ticket.php +++ b/app/ticket/model/Ticket.php @@ -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', diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index c9cbd17..ea97cef 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -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'] = '
  • 最新回复:' . $content . '
  • '; + } + 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'] = '
  • 最新回复:' . $conversation['content'] . '
  • '; + $notice['reply'] = '
  • 最新回复:' . '卡罗拉、极石01、比亚迪唐,宋Plus、丰田荣放、捷途T2、极氪7x、(阿联酋, 亚美尼亚, 阿塞拜疆, 白俄罗斯, 哥斯达黎加, 埃塞俄比亚, 格鲁吉亚, 加纳, 吉尔吉斯斯坦, 蒙古, 巴拉圭, 沙特阿拉伯, 塔吉克斯坦, 土库曼斯坦, 乌兹别克斯坦,委内瑞拉)起亚亦跑(阿尔及利亚),基本上每个车都推中亚中东南美非洲' . '
  • '; + } + + \app\common\utils\email\MailSend::send($email, '【XYH】新的工单提醒', replaceTpl($notice, 'work_order')); + return $email; + } + public function edit(array $data) { try { diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 5d451be..ce772df 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -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'], diff --git a/config/route.php b/config/route.php index b578322..6393f2d 100644 --- a/config/route.php +++ b/config/route.php @@ -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']);