From 9ae23153f640dee3accd6a870f7003aade5d651e Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 13 Aug 2025 17:00:16 +0800 Subject: [PATCH 01/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E5=8F=91=E9=80=81?= =?UTF-8?q?=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/scaffold/templates/workOrder.stub | 1 + app/ticket/logic/CategorieLogic.php | 8 +++++ app/ticket/logic/ConversationLogic.php | 14 ++++++++ app/ticket/service/ConversationService.php | 36 +++++++++++++++++++ app/ticket/service/TicketService.php | 3 ++ 5 files changed, 62 insertions(+) diff --git a/app/common/utils/scaffold/templates/workOrder.stub b/app/common/utils/scaffold/templates/workOrder.stub index c7b6ab0..9f592dd 100644 --- a/app/common/utils/scaffold/templates/workOrder.stub +++ b/app/common/utils/scaffold/templates/workOrder.stub @@ -80,6 +80,7 @@
  • 工单编号:{{code}}
  • 工单分类:{{category}}
  • 问题描述:{{content}}
  • + {{reply}}

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

    diff --git a/app/ticket/logic/CategorieLogic.php b/app/ticket/logic/CategorieLogic.php index c11bd64..f9f1014 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') + ->where('status',1) + ->where('locale', locale()) + ->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/service/ConversationService.php b/app/ticket/service/ConversationService.php index c9cbd17..ea52002 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; @@ -44,6 +47,39 @@ class ConversationService if (empty($data['content'])) { throw new BusinessException('消息内容不能为空'); } + + $conversation = (new ConversationLogic())->firstByTicket($data['ticket_id']); + $categorie= (new CategorieLogic())->find($data['categorie_id']); + $categorieName = isset($categorie['translation']) ? $categorie['translation']['name'] : ''; + + $notice = [ + 'code' => $data['code'], + 'category' => $categorieName, + 'content' => $data['content'], + 'reply' => '', + ]; + if (empty($conversation)) { + $email = 'app@hnxinyouhe.com'; + }else{ + $tiket = (new TicketLogic)->find($conversation['ticket_id']); + if($data['user_id'] != $tiket['user_id']){ + $email = User::find($tiket['user_id'])->value('email'); + }else{ + $conversationLast = Conversation::where('user_id', '=', $conversation['user_id']) + ->where('ticket_id', '=', $conversation['ticket_id']) + ->where('user_id', '!=', $conversation['user_id']) + ->orderBy('id', 'desc') + ->first(); + $email = User::find($conversationLast['user_id'])->value('email','app@hnxinyouhe.com'); + } + $notice['content'] = $tiket['content']; + $notice['reply'] = '
  • 最新回复:' . $data['content'] . '
  • '; + } + \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; diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 5d451be..d12c4e7 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -45,6 +45,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 +54,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'], From 39e840bba8a096981d86775cfa0f1983b68302d1 Mon Sep 17 00:00:00 2001 From: mzl Date: Thu, 14 Aug 2025 20:08:57 +0800 Subject: [PATCH 02/45] Merge branch 'develop' --- .../controller/CorpFeishuAppController.php | 33 ++ app/admin/controller/CountryController.php | 33 ++ app/admin/controller/RoleController.php | 100 +--- app/admin/controller/SystemsController.php | 16 +- app/admin/controller/UserController.php | 154 +++++- app/admin/logic/UserLogic.php | 76 +++ app/admin/service/CorpFeishuAppService.php | 70 +++ app/admin/service/CountryService.php | 31 ++ app/admin/service/RoleService.php | 19 + app/admin/service/UserService.php | 71 ++- app/command/CustomerCodeCommand.php | 3 +- app/common/controller/PresetController.php | 43 ++ app/common/controller/ResourceController.php | 82 +++ app/common/controller/UserController.php | 149 ++++-- app/common/logic/AuthLogic.php | 6 + app/common/logic/CorpFeishuAppLogic.php | 9 +- app/common/logic/CountryLogic.php | 17 + app/common/logic/PermLogic.php | 158 +----- app/common/logic/ResourceLogic.php | 37 ++ app/common/logic/RoleLogic.php | 79 ++- app/common/logic/UserLogic.php | 8 + app/common/model/CorpFeishuApp.php | 42 +- app/common/model/CrmCustomer.php | 27 + app/common/model/InquiryLog.php | 2 +- app/common/model/Resource.php | 51 +- app/common/model/User.php | 4 +- app/common/service/ResourceService.php | 172 +++--- app/common/service/UserService.php | 99 +++- app/common/traits/crud/CrudServiceTrait.php | 5 +- app/common/utils/Tree.php | 505 ++++++++++++++++++ app/common/utils/scaffold/Generate.php | 7 +- .../utils/scaffold/templates/workOrder.stub | 102 ++++ app/common/validate/CorpFeishuAppValidate.php | 29 + app/common/validate/CountryValidate.php | 29 + app/common/validate/ResourceValidate.php | 29 + app/common/validate/RoleValidate.php | 4 +- app/common/validate/UserValidate.php | 2 +- app/controller/IndexController.php | 56 +- app/crm/controller/CustomerController.php | 49 +- app/crm/model/Customer.php | 27 + app/crm/service/CustomerService.php | 23 +- .../controller/CustomerController.php | 53 ++ app/crmAdmin/logic/CustomerLogic.php | 8 +- app/crmAdmin/service/CustomerService.php | 66 ++- app/functions.php | 19 +- .../controller/StatisticsController.php | 2 +- app/queue/redis/InquiryToCrm.php | 1 + app/queue/redis/PermAgt.php | 95 ++++ config/route.php | 60 ++- 49 files changed, 2240 insertions(+), 522 deletions(-) create mode 100644 app/admin/controller/CorpFeishuAppController.php create mode 100644 app/admin/controller/CountryController.php create mode 100644 app/admin/service/CorpFeishuAppService.php create mode 100644 app/admin/service/CountryService.php create mode 100644 app/common/controller/ResourceController.php create mode 100644 app/common/logic/CountryLogic.php create mode 100644 app/common/logic/ResourceLogic.php create mode 100644 app/common/utils/Tree.php create mode 100644 app/common/utils/scaffold/templates/workOrder.stub create mode 100644 app/common/validate/CorpFeishuAppValidate.php create mode 100644 app/common/validate/CountryValidate.php create mode 100644 app/common/validate/ResourceValidate.php create mode 100644 app/queue/redis/PermAgt.php diff --git a/app/admin/controller/CorpFeishuAppController.php b/app/admin/controller/CorpFeishuAppController.php new file mode 100644 index 0000000..59e685d --- /dev/null +++ b/app/admin/controller/CorpFeishuAppController.php @@ -0,0 +1,33 @@ +service = new CorpFeishuAppService(); + } + + /** + * 列表页数据格式化 + * + * @param array $data + * @return array + */ + protected function indexFormat($data) + { + if (isset($data['created_at'])) + $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + if (isset($data['updated_at'])) + $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + return $data; + } +} \ No newline at end of file diff --git a/app/admin/controller/CountryController.php b/app/admin/controller/CountryController.php new file mode 100644 index 0000000..8cc8458 --- /dev/null +++ b/app/admin/controller/CountryController.php @@ -0,0 +1,33 @@ +service = new CountryService(); + } + + /** + * 列表页数据格式化 + * + * @param array $data + * @return array + */ + // protected function indexFormat($data) + // { + // if (isset($data['created_at'])) + // $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + // if (isset($data['updated_at'])) + // $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + // return $data; + // } +} \ No newline at end of file diff --git a/app/admin/controller/RoleController.php b/app/admin/controller/RoleController.php index 691e070..a08ff7e 100644 --- a/app/admin/controller/RoleController.php +++ b/app/admin/controller/RoleController.php @@ -5,6 +5,7 @@ namespace app\admin\controller; use app\common\controller\BaseController; use app\admin\service\RoleService; use app\common\traits\crud\CrudControllerTrait; +use support\Request; class RoleController extends BaseController { @@ -27,91 +28,16 @@ class RoleController extends BaseController return $data; } - // /** - // * 获取角色列表 - // */ - // public function list(Request $request) - // { - // try { - // $params = $request->all(); - // $result = (new RoleService())->getRoleList($params); - // // 定义后处理器 - // $postProcessor = function($formattedData) { - // if (isset($formattedData['created_at'])) - // $formattedData['created_at'] = date('Y-m-d H:i:s', $formattedData['created_at']); - // if (isset($formattedData['updated_at'])) - // $formattedData['updated_at'] = date('Y-m-d H:i:s', $formattedData['updated_at']); - // return $formattedData; - // }; - // return $this->success($this->transformData($result, $postProcessor), '角色列表获取成功'); - // } catch (\Throwable $e) { - // return $this->error($e->getMessage()); - // } - // } - // /** - // * 获取角色详情 - // */ - // public function detail(Request $request) - // { - // try { - // $roleId = $request->get('role_id'); - // if (!$roleId) { - // return $this->error('缺少角色ID', 422); - // } - // $result = (new RoleService())->getRoleDetail($roleId); - // return $this->success($result, '角色详情获取成功'); - // } catch (\Throwable $e) { - // return $this->error($e->getMessage()); - // } - // } - - // /** - // * 增加角色 - // */ - // public function create(Request $request) - // { - // try { - // $data = $this->validate(new RoleValidate(), $request->post(), 'role_create'); - // $result = (new RoleService())->createRole($data); - // return $this->success($result, '角色创建成功'); - // } catch (\think\exception\ValidateException $e) { - // return $this->error($e->getError(), 422); - // } catch (\Throwable $e) { - // return $this->error($e->getMessage()); - // } - // } - - // /** - // * 修改角色 - // */ - // public function update(Request $request) - // { - // try { - // $data = $this->validate(new RoleValidate(), $request->post(), 'role_update'); - // $result = (new RoleService())->updateRole($data); - // return $this->success($result, '角色更新成功'); - // } catch (\think\exception\ValidateException $e) { - // return $this->error($e->getError(), 422); - // } catch (\Throwable $e) { - // return $this->error($e->getMessage()); - // } - // } - - // /** - // * 删除角色 - // */ - // public function delete(Request $request) - // { - // try { - // $roleId = $request->get('role_id'); - // if (!$roleId) { - // return $this->error('缺少角色ID', 422); - // } - // (new RoleService())->deleteRole($roleId); - // return $this->success([], '角色删除成功'); - // } catch (\Throwable $e) { - // return $this->error($e->getMessage()); - // } - // } -} + public function menuResource(Request $request) + { + try { + // $data = $this->validate($this->service->getValidator(), $request->post(), 'allocation'); + $data = $request->post(); + $res = $this->service->menuResource($request, $data); + return $this->success($res); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/admin/controller/SystemsController.php b/app/admin/controller/SystemsController.php index 9c300ac..3c062c5 100644 --- a/app/admin/controller/SystemsController.php +++ b/app/admin/controller/SystemsController.php @@ -22,12 +22,12 @@ class SystemsController extends BaseController * @param array $data * @return array */ - // protected function indexFormat($data) - // { - // if (isset($data['created_at'])) - // $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); - // if (isset($data['updated_at'])) - // $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); - // return $data; - // } + protected function indexFormat($data) + { + if (isset($data['created_at'])) + $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + if (isset($data['updated_at'])) + $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + return $data; + } } \ No newline at end of file diff --git a/app/admin/controller/UserController.php b/app/admin/controller/UserController.php index dfcebd7..25f2385 100644 --- a/app/admin/controller/UserController.php +++ b/app/admin/controller/UserController.php @@ -6,6 +6,7 @@ use app\common\model\Corp; use app\common\traits\crud\CrudControllerTrait; use app\admin\service\UserService; use app\crm\model\Customer; +use support\Request; class UserController extends BaseController { @@ -17,6 +18,60 @@ class UserController extends BaseController { $this->service = new UserService(); } + /** + * 更新 + * + * @param Request $request 请求对象 + * @return mixed 返回更新成功的数据或信息 + */ + public function update(Request $request) + { + try { + $data = $request->post(); + $res = $this->service->serviceUpdateUser($request, $data); + return $this->success([], '更新成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 修改密码 + * @param Request $request + * @return \support\Response + * @throws \Random\RandomException + */ + public function savePassword(Request $request) + { + try { + $data = $request->all(); + if(empty($data['password'])){ + return $this->error('密码不能为空'); + } + $result = $this->service->savePassword($request,$data);; + return $this->success($result, '编辑成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 更新 + * + * @param Request $request 请求对象 + * @return mixed 返回更新成功的数据或信息 + */ + public function edit(Request $request) + { + try { + $data = $request->post(); + $data['id'] = $data['id']??$request->user->uid; + $res = $this->service->serviceUpdate($request, $data); + return $this->success([], '更新成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } /** * 列表页数据格式化 @@ -24,32 +79,79 @@ class UserController extends BaseController * @param array $data * @return array */ - protected function indexFormat($data) - { - if(isset($data['records'])){ - return $data; - } - $data['sex_txt'] = ''; - if (isset($data['sex']) && $data['sex'] == 1){ - $data['sex_txt'] = '男'; - }elseif(isset($data['sex']) && $data['sex'] == 2){ - $data['sex_txt'] = '女'; - } + protected function indexFormat($data) + { + if(isset($data['records'])){ + return $data; + } + $data['sex_txt'] = ''; + if (isset($data['sex']) && $data['sex'] == 1){ + $data['sex_txt'] = '男'; + }elseif(isset($data['sex']) && $data['sex'] == 2){ + $data['sex_txt'] = '女'; + } - switch ($data['status']){ - case 1: - $data['status_txt'] = '正常'; - break; - case 2: - $data['status_txt'] = '离职'; - break; - default: - $data['status_txt'] = ''; - break; - } + switch ($data['status']){ + case 1: + $data['status_txt'] = '正常'; + break; + case 2: + $data['status_txt'] = '离职'; + break; + default: + $data['status_txt'] = ''; + break; + } - $data['corp_name'] = Corp::where('id', $data['corp_id'])->value('name'); - $data['customer_count'] = Customer::where('user_id', $data['id'])->count(); - return $data; - } + $data['corp_name'] = Corp::where('id', $data['corp_id'])->value('name'); + $data['customer_count'] = Customer::where('user_id', $data['id'])->count(); + + $data['role_ids'] = []; + $data['system_ids'] = []; + if (isset($data['roles']) && count($data['roles']) > 0) { + foreach ($data['roles'] as $role) { + $data['role_ids'][] = $role['id']; + } + } + if (isset($data['systems']) && count($data['systems']) > 0) { + foreach ($data['systems'] as $system) { + $data['system_ids'][] = $system['id']; + } + } + return $data; + } + + /** + * 授权 + * + * @param Request $request + * @return mixed + */ + public function authorize(Request $request) + { + try { + $data = $request->post(); + $res = $this->service->authorize($request, $data); + return $this->success([], '分配成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 直接授权 + * + * @param Request $request + * @return mixed + */ + public function updateResources(Request $request) + { + try { + $data = $request->post(); + $res = $this->service->updateResources($request, $data); + return $this->success([], '分配成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } } \ No newline at end of file diff --git a/app/admin/logic/UserLogic.php b/app/admin/logic/UserLogic.php index de0d15d..d70b6de 100644 --- a/app/admin/logic/UserLogic.php +++ b/app/admin/logic/UserLogic.php @@ -4,6 +4,7 @@ namespace app\admin\logic; use app\common\traits\crud\CrudLogicTrait; use app\common\model\User; +use support\Db; class UserLogic { @@ -14,4 +15,79 @@ class UserLogic */ protected string $modelClass = User::class; + + public function updateRoleAndSystem(array $data): bool + { + $roleIds = $data['role_ids'] ?? []; + $systemIds = $data['system_ids'] ?? []; + $userId = $data['user_id'] ?? 0; + + Db::beginTransaction(); + try { + Db::table('user_roles')->where('user_id', $userId)->delete(); + if (count($roleIds) > 0) { + $insertDataRole = []; + foreach ($roleIds as $roleId) { + $insertDataRole[] = [ + 'role_id' => $roleId, + 'user_id' => $userId + ]; + } + Db::table('user_roles')->insert($insertDataRole); + } + + Db::table('user_systems')->where('user_id', $userId)->delete(); + if (count($systemIds) > 0) { + $insertDataSystem = []; + foreach ($systemIds as $systemId) { + $insertDataSystem[] = [ + 'system_id' => $systemId, + 'user_id' => $userId + ]; + } + Db::table('user_systems')->insert($insertDataSystem); + } + + Db::commit(); + return true; + } catch (\Throwable $exception) { + Db::rollBack(); + return false; + } + } + + + public function updateUserResources(array $data): bool + { + $userId = $data['user_id'] ?? 0; + $resources = $data['resources'] ?? []; + + if (empty($userId)) { + return false; + } + + Db::beginTransaction(); + try { + // 删除原有资源关联 + Db::table('user_resources')->where('user_id', $userId)->delete(); + + // 批量插入新角色资源关联 + if (!empty($resources)) { + $insertData = []; + foreach ($resources as $resourceId) { + $insertData[] = [ + 'user_id' => $userId, + 'resource_id' => $resourceId + ]; + } + Db::table('user_resources')->insert($insertData); + } + + Db::commit(); + return true; + } catch (\Throwable $exception) { + Db::rollBack(); + return false; + } + } } \ No newline at end of file diff --git a/app/admin/service/CorpFeishuAppService.php b/app/admin/service/CorpFeishuAppService.php new file mode 100644 index 0000000..e64631b --- /dev/null +++ b/app/admin/service/CorpFeishuAppService.php @@ -0,0 +1,70 @@ +validator; + } + + /** + * 构建查询条件 + */ + protected function buildQueryConfig(Request $request, string $scene = 'index'): array + { + $p = $request->all(); + + $config = []; + $config['model'] = $this->modelClass; + switch ($scene) { + case 'index': + $config['where']['status'] = 1; + $config['order']['sort'] = 'desc'; + $config['order']['id'] = 'desc'; + + $config['with']['corpInfo'][] = 'name'; + $config['with']['systemInfo'][] = 'name'; + break; + case 'show': + $config['where']['id'] = $p['id']; + $config['where']['status'] = 1; + + $config['with']['corpInfo'][] = 'name'; + $config['with']['systemInfo'][] = 'name'; + break; + case 'store': + break; + case 'update': + $config['where']['id'] = $p['id']; + break; + case 'destroy': + $config['where']['id'] = $p['id']; + break; + } + + return $config; + } +} \ No newline at end of file diff --git a/app/admin/service/CountryService.php b/app/admin/service/CountryService.php new file mode 100644 index 0000000..4139d97 --- /dev/null +++ b/app/admin/service/CountryService.php @@ -0,0 +1,31 @@ +validator; + } +} \ No newline at end of file diff --git a/app/admin/service/RoleService.php b/app/admin/service/RoleService.php index 248bc3d..f2ee190 100644 --- a/app/admin/service/RoleService.php +++ b/app/admin/service/RoleService.php @@ -2,9 +2,11 @@ namespace app\admin\service; +use app\common\logic\RoleLogic; use app\common\validate\RoleValidate; use app\common\traits\crud\CrudServiceTrait; use app\common\model\Role; +use support\Db; class RoleService { @@ -28,4 +30,21 @@ class RoleService { return new $this->validator; } + + /** + * 获取角色资源 + */ + public function menuResource($request, $data) + { + return (new RoleLogic)->updateRoleResources($data); + } + + + public function getList() + { + $config['where']['status'] = 1; + $config['order']['sort'] = 'asc'; + $config['order']['id'] = 'asc'; + return $this->logicListAll($config); + } } \ No newline at end of file diff --git a/app/admin/service/UserService.php b/app/admin/service/UserService.php index f2e07fd..4d23710 100644 --- a/app/admin/service/UserService.php +++ b/app/admin/service/UserService.php @@ -2,9 +2,11 @@ namespace app\admin\service; -use app\admin\validate\UserValidate; +use app\admin\logic\UserLogic; use app\common\traits\crud\CrudServiceTrait; use app\common\model\User; +use app\common\validate\UserValidate; +use support\exception\BusinessException; use support\Request; class UserService @@ -30,6 +32,25 @@ class UserService return new $this->validator; } + /** 更新 */ + public function serviceUpdateUser(Request $request, array $data = []) + { + $data = $this->preProcess('Update', $data, $request); + $config = $this->buildQueryConfig($request, 'update'); + $updated = $this->logicUpdateBy($config, $data); + return $this->postProcess('Update', $data); + } + + /** 更新 */ + public function serviceUpdate(Request $request, array $data = []) + { + unset($data['roles']); + unset($data['corp_name']); + $data = $this->preProcess('Update', $data, $request); + $config = $this->buildQueryConfig($request, 'edit'); + $updated = $this->logicUpdateBy($config, $data); + return $this->postProcess('Update', $data); + } /** * 构造 CrudUtil 查询配置 @@ -61,7 +82,12 @@ class UserService $config['where']['id'] = $p['id']; } - $config['fields'] = ['id','sn', 'name', 'email', 'sex', 'phone', 'avatar', 'corp_id', 'country_id', 'position', 'status', 'created_at']; + $config['fields'] = ['id','sn', 'name', 'email', 'sex', 'phone', 'avatar', 'corp_id', 'country_id', 'position', 'report_to', 'status', 'created_at']; + + $config['with']['roles'][] = 'id'; + $config['with']['roles'][] = 'name'; + $config['with']['systems'][] = 'id'; + $config['with']['systems'][] = 'name'; break; case 'show': $config['where']['id'] = $p['id']; @@ -74,8 +100,49 @@ class UserService case 'destroy': $config['where']['id'] = $p['id']; break; + case 'savePassword': + $config['where']['id'] = $p['id']; + break; + case 'edit': + $config['where']['id'] = $request->user->uid; + break; } return $config; } + + /** + * 授权 + * + * @param Request $request + * @param array $data + * @return bool + */ + public function authorize(Request $request, array $data = []) + { + return (new UserLogic())->updateRoleAndSystem($data); + } + + /** + * 更新用户资源权限 + * + * @param Request $request + * @param array $data + * @return bool + */ + public function updateResources(Request $request, array $data = []) + { + return (new UserLogic())->updateUserResources($data); + } + + /** + * 修改用户密码 + */ + public function savePassword(Request $request, array $data) + { + $config = $this->buildQueryConfig($request, 'savePassword'); + $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT); + $user = $this->logicUpdateBy($config,$data); + return $user; + } } \ No newline at end of file diff --git a/app/command/CustomerCodeCommand.php b/app/command/CustomerCodeCommand.php index 2d3e447..a82ec0f 100644 --- a/app/command/CustomerCodeCommand.php +++ b/app/command/CustomerCodeCommand.php @@ -44,7 +44,8 @@ class CustomerCodeCommand extends SymfonyCommand $code = 'CM' . $unique; } - $obtain = $customer->created_at>strtotime('2025-07-29')?$customer->created_at:strtotime('2025-07-29'); + $created_at = $customer->created_at->getTimestamp(); + $obtain = $created_at > strtotime('2025-07-29')?$created_at:strtotime('2025-07-29'); $customer->code = $code; $customer->obtain = $obtain; diff --git a/app/common/controller/PresetController.php b/app/common/controller/PresetController.php index ad88a8f..37073c4 100644 --- a/app/common/controller/PresetController.php +++ b/app/common/controller/PresetController.php @@ -2,11 +2,14 @@ namespace app\common\controller; +use app\admin\service\RoleService; use support\Request; use app\common\service\CorpService; use app\common\service\CorpFeishuAppService; use app\common\service\SystemsService; use app\common\service\UserService; +use support\Cache; +use app\common\service\PermService; class PresetController extends BaseController { @@ -61,4 +64,44 @@ class PresetController extends BaseController return $this->error($e->getMessage()); } } + + + public function roles() + { + try { + $result = (new RoleService)->getList(); + return $this->success($result, '获取角色列表'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + + public function cacheClear() + { + try { + Cache::clear(); + return $this->success([], '操作成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + public function menus(Request $request) + { + try { + $uid = $request->user->uid; + $systemCode = $request->system_code; + $permService = new PermService(); + $menuTree = $permService->getMenuTree($uid, $systemCode); + $permissionCodes = $permService->getPermissionCodes($uid, $systemCode); + $result = [ + 'menu' => $menuTree, + 'permissions' => $permissionCodes + ]; + return $this->success($result, '获取菜单权限'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } } \ No newline at end of file diff --git a/app/common/controller/ResourceController.php b/app/common/controller/ResourceController.php new file mode 100644 index 0000000..5fd35b9 --- /dev/null +++ b/app/common/controller/ResourceController.php @@ -0,0 +1,82 @@ +service = new ResourceService(); + } + + /** + * 列表页数据格式化 + * + * @param array $data + * @return array + */ + protected function allFormat($data) + { + if (isset($data['created_at'])) + $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']); + if (isset($data['updated_at'])) + $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']); + return $data; + } + + /** + * 资源树形结构 + */ + public function listTree(Request $request) + { + try { + $raw = $this->service->serviceListAll($request); + $data = $this->transformData($raw, method_exists($this, 'allFormat') + ? [$this, 'allFormat'] + : null); + return $this->success($data); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 菜单 + */ + public function menuList(Request $request) + { + try { + $raw = $this->service->serviceMenuList($request); + $data = $this->transformData($raw, method_exists($this, 'allFormat') + ? [$this, 'allFormat'] + : null); + return $this->success($data); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 菜单 + */ + public function menuTreeList(Request $request) + { + try { + $raw = $this->service->serviceMenuTreeList($request); + $data = $this->transformData($raw, method_exists($this, 'allFormat') + ? [$this, 'allFormat'] + : null); + return $this->success($data); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/common/controller/UserController.php b/app/common/controller/UserController.php index d725166..f49fba0 100644 --- a/app/common/controller/UserController.php +++ b/app/common/controller/UserController.php @@ -2,14 +2,63 @@ namespace app\common\controller; +use app\common\traits\crud\CrudControllerTrait; use support\Request; use app\common\service\UserService; class UserController extends BaseController { + use CrudControllerTrait; + + protected $service; + + public function __construct() + { + $this->service = new UserService(); + } + /** - * 用户信息 + * 获取组员列表 + * + * @param Request $request 请求对象 + * @return mixed 返回分页数据及总数 + */ + public function team(Request $request) + { + try { + $raw = $this->service->serviceTeam($request); + $data = $this->transformData($raw, method_exists($this, 'indexFormat') + ? [$this, 'indexFormat'] + : null); + return $this->success($data); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 标记组员离职 + * + * @param Request $request 请求对象 + * @return mixed 返回分页数据及总数 + */ + public function resignMember(Request $request) + { + try { + $userId = $request->get('user_id'); + if(empty($userId)){ + return $this->error('组员id不能为空'); + } + $user = $this->service->resignMember($request); + return $this->success($user, '获取用户信息'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 用户信息(登录后调用) */ public function info(Request $request) { @@ -23,57 +72,57 @@ class UserController extends BaseController } } - /** - * 用户信息 - */ - public function getUser(Request $request) - { - try { - $uid = $request->user->uid; - $corp_abbr = $request->basic_data['corp_abbr']; - $result = (new UserService())->getUser($uid,$corp_abbr); - return $this->success($result, '获取用户信息'); - } catch (\Throwable $e) { - return $this->error($e->getMessage()); - } - } + /** + * 用户信息 + */ + public function getUser(Request $request) + { + try { + $uid = $request->user->uid; + $corp_abbr = $request->basic_data['corp_abbr']; + $result = (new UserService())->getUser($uid,$corp_abbr); + return $this->success($result, '获取用户信息'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } - /** - * 编辑用户 - */ - public function edit(Request $request) - { - try { - $uid = $request->user->uid; - $data = $request->all(); - $result = (new UserService())->edit($uid,$data); - unset($result['password']); - unset($result['union_id']); - unset($result['open_id']); - unset($result['tenant_key']); - return $this->success($result, '编辑成功'); - } catch (\Throwable $e) { - return $this->error($e->getMessage()); - } - } + /** + * 编辑用户 + */ + public function edit(Request $request) + { + try { + $uid = $request->user->uid; + $data = $request->all(); + $result = (new UserService())->edit($uid,$data); + unset($result['password']); + unset($result['union_id']); + unset($result['open_id']); + unset($result['tenant_key']); + return $this->success($result, '编辑成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } - /** - * 修改密码 - * @param Request $request - * @return \support\Response - * @throws \Random\RandomException - */ - public function savePassword(Request $request) - { - try { - $uid = $request->user->uid; - $data = $request->all(); - $result = (new UserService())->savePassword($uid,$data);; - return $this->success($result, '编辑成功'); - } catch (\Throwable $e) { - return $this->error($e->getMessage()); - } - } + /** + * 修改密码 + * @param Request $request + * @return \support\Response + * @throws \Random\RandomException + */ + public function savePassword(Request $request) + { + try { + $uid = $request->user->uid; + $data = $request->all(); + $result = (new UserService())->savePassword($uid,$data);; + return $this->success($result, '编辑成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } } \ No newline at end of file diff --git a/app/common/logic/AuthLogic.php b/app/common/logic/AuthLogic.php index b2a74fc..9857df8 100644 --- a/app/common/logic/AuthLogic.php +++ b/app/common/logic/AuthLogic.php @@ -118,6 +118,12 @@ class AuthLogic } // 是否登陆 $user->isLogin = false; + + $options = [ + 'corp_id' => $user->corp_id, + 'user_id' => $user->id + ]; + \Webman\RedisQueue\Redis::send('perm-agt', $options); } else { $updated = [ 'union_id' => $feishuUserInfo['union_id'], diff --git a/app/common/logic/CorpFeishuAppLogic.php b/app/common/logic/CorpFeishuAppLogic.php index e246316..2613c6a 100644 --- a/app/common/logic/CorpFeishuAppLogic.php +++ b/app/common/logic/CorpFeishuAppLogic.php @@ -2,11 +2,18 @@ namespace app\common\logic; +use app\common\traits\crud\CrudLogicTrait; use app\common\model\CorpFeishuApp; class CorpFeishuAppLogic { - + use CrudLogicTrait; + + /** + * 指定当前要操作的模型 + */ + protected string $modelClass = CorpFeishuApp::class; + public function getFeishuApp($corpId, $systemId) { diff --git a/app/common/logic/CountryLogic.php b/app/common/logic/CountryLogic.php new file mode 100644 index 0000000..0a753ee --- /dev/null +++ b/app/common/logic/CountryLogic.php @@ -0,0 +1,17 @@ +roles as $role) { $all = $all->merge( + // 过滤当前角色的资源列表 $role->resources->filter(function ($resource) use($system) { - // var_dump($resource->toArray()); - // 只保留需要权限认证的资源(或公共资源) + // 资源过滤条件: + // 1. !$resource->no_auth:资源需要权限认证(排除公共资源) + // 2. 系统匹配条件: + // - $system->id == $resource->system_id:资源属于当前系统 + // - $resource->system_id == 0:资源为全局公共资源(所有系统可用) return !$resource->no_auth && ($system->id == $resource->system_id || $resource->system_id == 0); }) ); @@ -64,151 +67,6 @@ class PermLogic * @param string $parentPath 父级完整路径(用于递归) * @return array */ - public function buildTree_bak($resources, int $parentId = 0, string $parentPath = ''): array - { - $tree = []; - - foreach ($resources as $node) { - // 只处理目录和菜单,不把 permission 当作菜单节点 - if ($node->parent_id !== $parentId || $node->type === 'permission') { - continue; - } - - // —— 拼接当前节点的完整路径 —— - $currentPath = rtrim($parentPath, '/'); - if (!empty($node->url)) { - $urlSegment = ltrim($node->url, '/'); - $currentPath = $currentPath === '' - ? $urlSegment - : "{$currentPath}/{$urlSegment}"; - } - - // —— 递归构建子节点 —— - // 这里只会继续收目录和菜单,permission 永远不会进入此方法 - $children = $this->buildTree($resources, $node->id, $currentPath); - - // —— 本级权限列表 —— - $authList = $resources - ->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id) - ->map(fn($r) => [ - 'id' => $r->id, - 'title' => $r->name, - 'auth_mark' => $r->code, - ]) - ->values() - ->all(); - - // —— 判断是否有子目录或子菜单 —— - $hasChildrenMenu = ! empty($children); - - // —— 计算 component 字段 —— - if ($hasChildrenMenu) { - if ($node->type === 'menu' && !empty($node->url)) { - // menu 类型且自身有 url,用自身 url(加前导 slash) - $componentValue = '/' . ltrim($node->url, '/'); - } else { - // 其它含子项的节点,固定 Layout 组件 - $componentValue = '/index/index'; - } - } else { - // 叶子节点:拼接路径,确保以 slash 开头 - $componentValue = $currentPath !== '' - ? '/' . ltrim($currentPath, '/') - : ''; - } - - $tree[] = [ - 'id' => $node->id, - 'name' => $node->name, - 'path' => $node->url, - 'component' => $componentValue, - 'meta' => [ - 'title' => $node->name, - 'icon' => $node->icon, - 'keepAlive' => true, - 'authList' => $authList, - 'openType' => $node->open_type, - 'isHide' => $node->is_hide == 0 ? false : true, - 'isHideTab' => $node->is_hide_tab == 0 ? false : true - ], - 'children' => $children - ]; - } - - return $tree; - } - public function buildTree_bak2($resources, int $parentId = 0, string $parentPath = ''): array - { - $tree = []; - - foreach ($resources as $node) { - if ($node->parent_id !== $parentId) { - continue; - } - - // —— 拼接当前节点的完整路径 —— - $currentPath = $parentPath; - // 去掉末尾多余 slash - $currentPath = rtrim($currentPath, '/'); - - if (!empty($node->url)) { - // 如果当前节点有 url,则拼接 - $urlSegment = ltrim($node->url, '/'); - $currentPath = $currentPath === '' - ? $urlSegment - : "{$currentPath}/{$urlSegment}"; - } - - // —— 递归构建子节点 —— - $children = []; - if ($node->type === 'directory') { - $children = $this->buildTree($resources, $node->id, $currentPath); - } - - // —— 收集本级的 permission 权限列表 —— - $authList = $resources - ->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id) - ->map(fn($r) => [ - 'id' => $r->id, - 'title' => $r->name, - 'auth_mark' => $r->code, - ]) - ->values() - ->all(); - - // —— 判断是否有子菜单/目录 —— - $hasChildrenMenu = $resources - ->where('parent_id', $node->id) - ->whereIn('type', ['directory', 'menu']) - ->isNotEmpty(); - - // —— 计算 component 字段 —— - if ($hasChildrenMenu) { - // 只要有子项,就一律显示顶层 Layout 组件 - $componentValue = '/index/index'; - } else { - // 叶子节点:如果定义了 url,就使用拼接后的路径;否则用占位符(这里用空串,你可替换) - $componentValue = $currentPath !== '' ? $currentPath : ''; - } - - $tree[] = [ - 'id' => $node->id, - 'name' => $node->name, - 'path' => $node->url, - 'component' => $componentValue, - 'meta' => [ - 'title' => $node->name, - 'icon' => $node->icon, - 'keepAlive' => true, - 'authList' => $authList, - 'openType' => $node->open_type, - ], - 'children' => $children, - ]; - } - - return $tree; - } public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array { $tree = []; @@ -258,7 +116,7 @@ class PermLogic 'meta' => [ 'title' => $node->name, 'icon' => $node->icon, - 'keepAlive' => true, + 'keepAlive' => $node->keep_alive == 1 ? true : false, 'authList' => $authList, 'openType' => $node->open_type, 'isHide' => $node->is_hide == 0 ? false : true, diff --git a/app/common/logic/ResourceLogic.php b/app/common/logic/ResourceLogic.php new file mode 100644 index 0000000..ddf6423 --- /dev/null +++ b/app/common/logic/ResourceLogic.php @@ -0,0 +1,37 @@ +logicListAll($config); + + if ($request->get('role_id')) { + $selected = (new RoleLogic())->getRoleResources($request->get('role_id')); + } else if ($request->get('user_id')) { + $selected = (new RoleLogic())->getUserResources($request->get('user_id')); + } else { + $selected = []; + } + + foreach ($data as &$item) { + $item['selected'] = in_array($item['id'], $selected) ? true : false; + } + + return $data; + } +} \ No newline at end of file diff --git a/app/common/logic/RoleLogic.php b/app/common/logic/RoleLogic.php index bd8f121..0898b10 100644 --- a/app/common/logic/RoleLogic.php +++ b/app/common/logic/RoleLogic.php @@ -2,13 +2,84 @@ namespace app\common\logic; -use app\common\model\Role; -use support\exception\BusinessException; -use support\Log; +use support\Db; class RoleLogic { - + /** + * 更新角色资源权限 + * + * @param array $data 包含 role_id 和 resources 的数据 + * @return bool 操作是否成功 + */ + public function updateRoleResources(array $data): bool + { + $roleId = $data['role_id'] ?? 0; + $resources = $data['resources'] ?? []; + + if (empty($roleId)) { + return false; + } + + Db::beginTransaction(); + try { + // 删除原有角色资源关联 + Db::table('role_resources')->where('role_id', $roleId)->delete(); + + // 批量插入新角色资源关联 + if (!empty($resources)) { + $insertData = []; + foreach ($resources as $resourceId) { + $insertData[] = [ + 'role_id' => $roleId, + 'resource_id' => $resourceId + ]; + } + Db::table('role_resources')->insert($insertData); + } + + Db::commit(); + return true; + } catch (\Throwable $exception) { + Db::rollBack(); + return false; + } + } + /** + * 获取角色资源 + * + * @param int $roleId 角色ID + * @return array 资源ID列表 + */ + public function getRoleResources(int $roleId): array + { + if (empty($roleId)) { + return []; + } + + return Db::table('role_resources') + ->where('role_id', $roleId) + ->pluck('resource_id') + ->toArray(); + } + + /** + * 获取用户资源 + * + * @param int $userId 用户ID + * @return array 资源ID列表 + */ + public function getUserResources(int $userId): array + { + if (empty($userId)) { + return []; + } + + return Db::table('user_resources') + ->where('user_id', $userId) + ->pluck('resource_id') + ->toArray(); + } } diff --git a/app/common/logic/UserLogic.php b/app/common/logic/UserLogic.php index 9f5ae44..c7d5343 100644 --- a/app/common/logic/UserLogic.php +++ b/app/common/logic/UserLogic.php @@ -3,10 +3,18 @@ namespace app\common\logic; use app\common\model\User; +use app\common\traits\crud\CrudLogicTrait; use support\exception\BusinessException; class UserLogic { + use CrudLogicTrait; + + /** + * 指定当前要操作的模型 + */ + protected string $modelClass = User::class; + /** * 用户信息 */ diff --git a/app/common/model/CorpFeishuApp.php b/app/common/model/CorpFeishuApp.php index 44a83ea..8019a0b 100644 --- a/app/common/model/CorpFeishuApp.php +++ b/app/common/model/CorpFeishuApp.php @@ -4,24 +4,6 @@ namespace app\common\model; use support\Model; -/** - * corp_feishu_app 企业-飞书应用 - * @property integer $id ID(主键) - * @property integer $corp_id 公司ID - * @property string $name 名称 - * @property string $tenant_key 企业标识 - * @property string $app_id 应用ID - * @property string $app_secret 应用秘钥 - * @property string $base_uri 基础域 - * @property string $r_url 授权地址 - * @property string $scopes 授权范围 - * @property string $state 携带参数 - * @property string $system_code 绑定系统码 - * @property integer $sort 排序 - * @property integer $status 状态 - * @property integer $created_at 创建时间 - * @property integer $updated_at 更新时间 - */ class CorpFeishuApp extends Model { /** @@ -53,4 +35,26 @@ class CorpFeishuApp extends Model public $timestamps = true; -} + protected $dateFormat = 'U'; + + /** + * 允许自动填充模型字段 + */ + protected $fillable = ['id', 'corp_id', 'system_id', 'name', 'tenant_key', 'app_id', 'app_secret', 'base_uri', 'r_url', 'scopes', 'state', 'sort', 'status', 'created_at', 'updated_at']; + + /** + * 不允许自动填充模型字段 + */ + protected $guarded = []; + + + public function corpInfo() + { + return $this->hasOne(Corp::class, 'id', 'corp_id'); + } + + public function systemInfo() + { + return $this->hasOne(Systems::class, 'id', 'system_id'); + } +} \ No newline at end of file diff --git a/app/common/model/CrmCustomer.php b/app/common/model/CrmCustomer.php index 49446e6..bc439db 100644 --- a/app/common/model/CrmCustomer.php +++ b/app/common/model/CrmCustomer.php @@ -46,4 +46,31 @@ class CrmCustomer extends Model * 不允许自动填充模型字段 */ protected $guarded = []; + + protected static function booted() + { + static::saved(function ($customer) { + if (empty($customer->code)) { + $customer->code = self::generateCustomerCode($customer); + // 使用saveQuietly避免递归调用 + $customer->saveQuietly(); + } + }); + } + + public static function generateCustomerCode($customer) + { + // 生成唯一16位code,CM+14位 + $unique = strtoupper(substr(md5($customer->id . microtime(true) . mt_rand(1000, 9999)), 8, 6)); + $code = 'CM' . date('Ymd') .$unique; + return $code; + } + + // 静默保存方法,不触发事件 + public function saveQuietly(array $options = []) + { + return static::withoutEvents(function () use ($options) { + return $this->save($options); + }); + } } \ No newline at end of file diff --git a/app/common/model/InquiryLog.php b/app/common/model/InquiryLog.php index 68926aa..798b267 100644 --- a/app/common/model/InquiryLog.php +++ b/app/common/model/InquiryLog.php @@ -62,7 +62,7 @@ class InquiryLog extends Model public function recipientInfo() { - return $this->hasOne(User::class, 'id', 'recipient'); + return $this->hasOne(User::class, 'id', 'recipient')->where('status', 1); } public function channelInfo() diff --git a/app/common/model/Resource.php b/app/common/model/Resource.php index 6fc54d9..bff7b0a 100644 --- a/app/common/model/Resource.php +++ b/app/common/model/Resource.php @@ -4,20 +4,6 @@ namespace app\common\model; use support\Model; -/** - * resources 资源表:目录/菜单/权限 - * @property integer $id 资源ID(主键) - * @property string $name 资源名称 - * @property string $type 资源类型 - * @property string $code 资源编码(权限标识) - * @property integer $parent_id 父资源ID - * @property string $url 路由 path 或 外链 URL - * @property string $icon 图标,仅目录/菜单有效 - * @property string $open_type 菜单打开方式 - * @property integer $sort 排序 - * @property string $created_at - * @property string $updated_at - */ class Resource extends Model { /** @@ -49,32 +35,15 @@ class Resource extends Model public $timestamps = true; - // 所属系统 - public function system() - { - return $this->belongsTo(Systems::class, 'system_id', 'id'); - } + protected $dateFormat = 'U'; - // 拥有该资源的角色 - public function roles() - { - return $this->belongsToMany(Role::class, 'role_resources', 'resource_id', 'role_id'); - } + /** + * 允许自动填充模型字段 + */ + protected $fillable = ['id', 'system_id', 'name', 'desc', 'type', 'code', 'parent_id', 'url', 'icon', 'open_type', 'is_hide', 'is_hide_tab', 'no_auth', 'is_home', 'instance', 'sort', 'status', 'created_at', 'updated_at']; - // 拥有该资源的用户(特殊补权) - public function users() - { - return $this->belongsToMany(User::class, 'user_resources', 'resource_id', 'user_id'); - } - - // 递归 - public function parent() - { - return $this->belongsTo(self::class, 'parent_id'); - } - - public function children() - { - return $this->hasMany(self::class, 'parent_id'); - } -} + /** + * 不允许自动填充模型字段 + */ + protected $guarded = []; +} \ No newline at end of file diff --git a/app/common/model/User.php b/app/common/model/User.php index 446ed46..88c670d 100644 --- a/app/common/model/User.php +++ b/app/common/model/User.php @@ -15,7 +15,8 @@ use support\Model; * @property string $email 邮箱 * @property integer $status 状态 * @property string $system_code 系统码 - * @property string $created_at + * @property string $report_to 上级用户ID + * @property string $created_at * @property string $updated_at */ class User extends Model @@ -69,6 +70,7 @@ class User extends Model 'position', 'socialize', 'socialize_pic', + 'report_to', ]; // 用户所有角色 diff --git a/app/common/service/ResourceService.php b/app/common/service/ResourceService.php index dce3bb1..ad3f85b 100644 --- a/app/common/service/ResourceService.php +++ b/app/common/service/ResourceService.php @@ -2,82 +2,128 @@ namespace app\common\service; -use app\model\User; -use app\model\Role; -use app\model\Resource; +use app\common\logic\ResourceLogic; +use app\common\validate\ResourceValidate; +use app\common\traits\crud\CrudServiceTrait; +use app\common\model\Resource; +use app\common\utils\Tree; +use support\Request; class ResourceService { - /** - * 获取用户可见菜单树 - */ - public static function getMenuTreeForUser($userId) - { - $menuList = self::getUserMenus($userId); - // 转树 - return self::buildTree($menuList); - } + + use CrudServiceTrait; /** - * 获取用户所有有权限的菜单资源(type=menu) + * 指定当前要操作的模型 */ - public static function getUserMenus($userId) - { - $user = User::with('roles.resources')->find($userId); - if (!$user) return []; - // 合并所有角色下的菜单资源 - $allMenus = []; - foreach ($user->roles as $role) { - foreach ($role->resources as $res) { - if ($res->type === 'menu') { - $allMenus[$res->id] = $res; - } - } - } - return array_values($allMenus); // 去重后返回 - } + protected string $modelClass = Resource::class; /** - * 获取用户所有有权限的按钮/功能权限 code + * 验证器 */ - public static function getButtonPermissionCodesForUser($userId) - { - $user = User::with('roles.resources')->find($userId); - if (!$user) return []; - $codes = []; - foreach ($user->roles as $role) { - foreach ($role->resources as $res) { - if ($res->type === 'button' && $res->code) { - $codes[$res->code] = true; - } - } - } - return array_keys($codes); // 去重后返回权限code数组 - } + protected $validator = ResourceValidate::class; /** - * 递归构建菜单树 - * @param Resource[] $list - * @param int $parentId - * @return array + * 获取验证器 */ - protected static function buildTree($list, $parentId = 0) + public function getValidator() { - $tree = []; - foreach ($list as $item) { - if ($item->parent_id == $parentId) { - $children = self::buildTree($list, $item->id); - $arr = [ - 'id' => $item->id, - 'name' => $item->name, - 'path' => $item->url, - 'icon' => $item->icon ?? null, - 'code' => $item->code, - 'children' => $children, - ]; - $tree[] = $arr; - } + return new $this->validator; + } + + + protected function buildQueryConfig(Request $request, string $scene = 'default'): array + { + $p = $request->all(); + + $config = []; + $config['model'] = $this->modelClass; + switch ($scene) { + case 'default': + $config['where']['system_id'] = ['in', [0, $p['system_id']]]; + $config['where']['status'] = 1; + $config['order']['sort'] = 'asc'; + $config['order']['id'] = 'asc'; + break; + case 'menuList': + $config['where']['status'] = 1; + $config['where']['type'] = ['!=', 'permission']; + $config['order']['sort'] = 'asc'; + $config['order']['id'] = 'asc'; + break; + case 'menuTreeList': + $config['where']['status'] = 1; + $config['order']['sort'] = 'asc'; + $config['order']['id'] = 'asc'; + break; + case 'index': + $config['where']['status'] = 1; + $config['order']['sort'] = 'asc'; + $config['order']['id'] = 'asc'; + break; + case 'show': + $config['where']['id'] = $p['id']; + $config['where']['status'] = 1; + break; + case 'store': + break; + case 'update': + $config['where']['id'] = $p['id']; + break; + case 'destroy': + $config['where']['id'] = $p['id']; + break; } - return $tree; + + return $config; + } + + public function serviceMenuList(Request $request) + { + $config = $this->buildQueryConfig($request, 'menuList'); + $result = $this->logicListAll($config); + return $this->postProcess('MenuList', $result); + } + + public function serviceMenuTreeList(Request $request) + { + $config = $this->buildQueryConfig($request, 'menuTreeList'); + $result = (new ResourceLogic())->logicListAllResources($request, $config); + return $this->postProcess('MenuTreeList', $result); + } + + + protected function afterServiceListAll($data) + { + $data = Tree::buildMenuTreeWithReference($data->toArray()); + return $data; + } + + protected function afterServiceMenuList($data) + { + $data = Tree::buildMenuTree($data->toArray()); + return $data; + } + + protected function afterServiceMenuTreeList($data) + { + $data = Tree::buildMenuTree($data->toArray()); + return $data; + } + + + public function beforeServiceStore($data, Request $request) + { + $data['parent_id'] = $data['parent_id'] != '' ? $data['parent_id'] : 0; + $data['system_id'] = $data['system_id'] != '' ? $data['system_id'] : 0; + return $data; + } + + public function beforeServiceUpdate($data, Request $request) + { + $data['parent_id'] = $data['parent_id'] != '' ? $data['parent_id'] : 0; + $data['system_id'] = $data['system_id'] != '' ? $data['system_id'] : 0; + return $data; } } \ No newline at end of file diff --git a/app/common/service/UserService.php b/app/common/service/UserService.php index 1d5dab4..53507b2 100644 --- a/app/common/service/UserService.php +++ b/app/common/service/UserService.php @@ -5,12 +5,22 @@ namespace app\common\service; use app\common\logic\UserLogic; use app\common\model\Corp; use app\common\model\User; +use app\common\traits\crud\CrudLogicTrait; +use app\common\traits\crud\CrudServiceTrait; use app\common\utils\CrudUtil; use app\crm\model\Country; +use app\crm\model\Customer; use support\exception\BusinessException; +use support\Request; class UserService { + use CrudServiceTrait; + + /** + * 指定当前要操作的模型 + */ + protected string $modelClass = User::class; protected $logic; @@ -25,9 +35,10 @@ class UserService public function getUserInfo(int $uid, string $systemCode) { $user = $this->logic->userInfo($uid); - $permService = new PermService(); - $menuTree = $permService->getMenuTree($uid, $systemCode); - $permissionCodes = $permService->getPermissionCodes($uid, $systemCode); + // $permService = new PermService(); + // $menuTree = $permService->getMenuTree($uid, $systemCode); + // $permissionCodes = $permService->getPermissionCodes($uid, $systemCode); + $corp_name = Corp::where('abbr', $user->corp_id)->value('name'); return [ 'user' => [ 'id' => $user->id, @@ -36,10 +47,14 @@ class UserService 'phone' => $user->phone, 'email' => $user->email, 'status' => $user->status, - 'roles' => $user->roles->pluck('name') + 'roles' => $user->roles->pluck('name'), + 'sex' => $user->sex, + 'sn' => $user->sn, + 'corp_id' => $user->corp_id, + 'corp_name' => $corp_name, ], - 'menu' => $menuTree, - 'permissions' => $permissionCodes + // 'menu' => $menuTree, + // 'permissions' => $permissionCodes ]; } @@ -110,4 +125,76 @@ class UserService { return $this->logic->getList(); } + + /** 分页列表 */ + public function serviceTeam(Request $request) + { + if (method_exists($this, 'complexQuery')) { + $result = $this->complexQuery($request->get()); + } else { + $config = $this->buildQueryConfig($request, 'team'); + $limit = (int)$request->get('size', 15); + $page = (int)$request->get('current', 1); + $result = $this->logicList($config, $limit, $page); + } + + foreach ($result as &$data){ + $data['customer_count'] = Customer::where('user_id', $data['id'])->count(); + unset($data['password']); + unset($data['open_id']); + unset($data['tenant_key']); + unset($data['union_id']); + } + + return $this->postProcess('List', $result); + } + + /** 分页列表 */ + public function resignMember(Request $request) + { + $uid = $request->user->uid; + $userId = $request->get('user_id'); + $user = User::find($userId); + if ($user->report_to != $uid) { + throw new BusinessException('禁止操作非组员'); + } + + $data = [ + 'status' => 2, + ]; + $user = $this->logic->edit($userId,$data); + $user = $user->toArray(); + unset($user['password']); + unset($user['open_id']); + unset($user['tenant_key']); + unset($user['union_id']); + return $user; + } + + /** + * 构造 CrudUtil 查询配置 + */ + protected function buildQueryConfig(Request $request, string $scene = 'default'): array + { + $p = $request->all(); + + $config = []; + $config['model'] = $this->modelClass; + switch ($scene) { + case 'team': +// $config['where']['status'] = 1; // 关键字 + $config['order']['id'] = 'desc'; + + if (isset($p['status']) && $p['status']) { + $config['where']['status'] = $p['status']; + } + + $config['dataLimit']['type'] = 'relation'; + $config['dataLimit']['userId'] = $request->user->uid; + $config['dataLimit']['userField'] = 'report_to'; + break; + } + + return $config; + } } \ No newline at end of file diff --git a/app/common/traits/crud/CrudServiceTrait.php b/app/common/traits/crud/CrudServiceTrait.php index 344756d..dd4536f 100644 --- a/app/common/traits/crud/CrudServiceTrait.php +++ b/app/common/traits/crud/CrudServiceTrait.php @@ -1,6 +1,7 @@ buildQueryConfig($request, 'default'); $result = $this->logicListAll($config); } - return $this->postProcess('List', $result); + return $this->postProcess('ListAll', $result); } /** 查看单条 */ @@ -188,6 +189,6 @@ trait CrudServiceTrait */ // protected function complexQuery(array $params): array // { - // throw new \LogicException('请在子类实现 complexQuery'); + // throw new BusinessException('请在子类实现 complexQuery'); // } } \ No newline at end of file diff --git a/app/common/utils/Tree.php b/app/common/utils/Tree.php new file mode 100644 index 0000000..b831185 --- /dev/null +++ b/app/common/utils/Tree.php @@ -0,0 +1,505 @@ + $item) { + // if ($item[$pidField] == 0) { + // $tree[] = &$items[$id]; + // } else { + // if (isset($items[$item[$pidField]])) { + // $items[$id]['level'] = $items[$item[$pidField]]['level'] + 1; + + // if (!isset($items[$item[$pidField]]['children'])) { + // $items[$item[$pidField]]['children'] = []; + // } + + // $items[$item[$pidField]]['children'][] = &$items[$id]; + // } + // } + // } + + // return $tree; + // } + + // /** + // * 将树形结构扁平化为列表(带层级前缀) + // * + // * @param array $tree 树形结构数据 + // * @param string $prefix 前缀字符 + // * @param string $field 显示字段名 + // * @param int $level 层级 + // * @return array + // */ + // public static function flattenWithPrefix(array $tree, string $prefix = '--', string $field = 'name', int $level = 0): array + // { + // $result = []; + + // foreach ($tree as $item) { + // $item[$field . '_with_prefix'] = str_repeat($prefix, $item['level']) . $item[$field]; + // $result[] = $item; + + // if (isset($item['children']) && !empty($item['children'])) { + // $children = static::flattenWithPrefix($item['children'], $prefix, $field, $item['level'] + 1); + // $result = array_merge($result, $children); + // } + // } + + // return $result; + // } + + // /** + // * 根据父ID查找所有子节点(包括子孙节点) + // * + // * @param array $data 数据列表 + // * @param int $parentId 父级ID + // * @param string $pidField 父级字段名 + // * @param string $idField ID字段名 + // * @return array + // */ + // public static function findChildren(array $data, int $parentId, string $pidField = 'parent_id', string $idField = 'id'): array + // { + // $children = []; + + // foreach ($data as $item) { + // if ($item[$pidField] == $parentId) { + // $children[] = $item; + // $grandChildren = static::findChildren($data, $item[$idField], $pidField, $idField); + // $children = array_merge($children, $grandChildren); + // } + // } + + // return $children; + // } + + // /** + // * 获取指定节点的所有父级节点 + // * + // * @param array $data 数据列表 + // * @param int $id 当前节点ID + // * @param string $pidField 父级字段名 + // * @param string $idField ID字段名 + // * @return array + // */ + // public static function getParents(array $data, int $id, string $pidField = 'parent_id', string $idField = 'id'): array + // { + // $parents = []; + + // foreach ($data as $item) { + // if ($item[$idField] == $id) { + // if ($item[$pidField] != 0) { + // $parents[] = $item; + // $parentParents = static::getParents($data, $item[$pidField], $pidField, $idField); + // $parents = array_merge($parents, $parentParents); + // } + // break; + // } + // } + + // return $parents; + // } + + // /** + // * 获取指定节点的子孙节点ID列表 + // * + // * @param array $data 数据列表 + // * @param int $parentId 父级ID + // * @param string $pidField 父级字段名 + // * @param string $idField ID字段名 + // * @return array + // */ + // public static function getChildrenIds(array $data, int $parentId, string $pidField = 'parent_id', string $idField = 'id'): array + // { + // $ids = []; + // $children = static::findChildren($data, $parentId, $pidField, $idField); + + // foreach ($children as $child) { + // $ids[] = $child[$idField]; + // } + + // return $ids; + // } + + // /** + // * 检查是否有子节点 + // * + // * @param array $data 数据列表 + // * @param int $parentId 父级ID + // * @param string $pidField 父级字段名 + // * @return bool + // */ + // public static function hasChildren(array $data, int $parentId, string $pidField = 'parent_id'): bool + // { + // foreach ($data as $item) { + // if ($item[$pidField] == $parentId) { + // return true; + // } + // } + + // return false; + // } + + + // /** + // * 构建带有权限列表的资源树(权限不显示在树结构中) + // * + // * @param array $data 资源数据列表 + // * @param int $parentId 父级ID + // * @param string $pidField 父级字段名 + // * @param string $idField ID字段名 + // * @param string $typeField 类型字段名 + // * @param string $permissionType 权限类型标识 + // * @param int $level 当前层级 + // * @return array + // */ + // public static function buildWithAuthList( + // array $data, + // int $parentId = 0, + // string $pidField = 'parent_id', + // string $idField = 'id', + // string $typeField = 'type', + // string $permissionType = 'permission', + // int $level = 0 + // ): array { + // $tree = []; + + // foreach ($data as $item) { + // // 只处理指定父级的非权限节点 + // if ($item[$pidField] == $parentId && $item[$typeField] != $permissionType) { + // $item['level'] = $level; + + // // 递归处理子节点(非权限类型) + // $children = static::buildWithAuthList($data, $item[$idField], $pidField, $idField, $typeField, $permissionType, $level + 1); + + // if (!empty($children)) { + // $item['children'] = $children; + // } + + // // 收集当前节点下的所有权限 + // $item['auth_list'] = static::collectDirectPermissions($data, $item[$idField], $pidField, $typeField, $permissionType); + + // $tree[] = $item; + // } + // } + + // return $tree; + // } + + // /** + // * 收集指定节点下的直接权限项(只收集直接子节点中的权限) + // * + // * @param array $data 数据列表 + // * @param int $parentId 父级ID + // * @param string $pidField 父级字段名 + // * @param string $typeField 类型字段名 + // * @param string $permissionType 权限类型标识 + // * @return array + // */ + // public static function collectDirectPermissions1( + // array $data, + // int $parentId, + // string $pidField = 'parent_id', + // string $typeField = 'type', + // string $permissionType = 'permission' + // ): array { + // $permissions = []; + + // foreach ($data as $item) { + // // 收集直接子节点中的权限类型 + // if ($item[$pidField] == $parentId && $item[$typeField] == $permissionType) { + // $permissions[] = $item; + // } + // } + + // return $permissions; + // } + + // /** + // * 使用引用方式构建带有权限列表的资源树(权限不显示在树结构中) + // * + // * @param array $data 资源数据列表 + // * @param string $pidField 父级字段名 + // * @param string $idField ID字段名 + // * @param string $typeField 类型字段名 + // * @param string $permissionType 权限类型标识 + // * @return array + // */ + // public static function buildWithAuthListAndReference( + // array $data, + // string $pidField = 'parent_id', + // string $idField = 'id', + // string $typeField = 'type', + // string $permissionType = 'permission' + // ): array { + // $items = []; + // $tree = []; + + // // 建立以id为索引的数组(只包含非权限节点) + // foreach ($data as $item) { + // if ($item[$typeField] != $permissionType) { + // $item['level'] = 0; + // $items[$item[$idField]] = $item; + // } + // } + + // // 构建树形结构 + // foreach ($items as $id => $item) { + // if ($item[$pidField] == 0) { + // $tree[] = &$items[$id]; + // } else { + // if (isset($items[$item[$pidField]])) { + // $items[$id]['level'] = $items[$item[$pidField]]['level'] + 1; + + // if (!isset($items[$item[$pidField]]['children'])) { + // $items[$item[$pidField]]['children'] = []; + // } + + // $items[$item[$pidField]]['children'][] = &$items[$id]; + // } + // } + // } + + // // 为每个节点添加权限列表 + // foreach ($items as &$item) { + // $item['auth_list'] = static::collectDirectPermissions($data, $item[$idField], $pidField, $typeField, $permissionType); + // } + + // return $tree; + // } + + + + // 8.13 add + /** + * 构建前端需要的菜单树结构 + * + * @param array $data 服务端菜单数据 + * @param int $parentId 父级ID + * @return array + */ + public static function buildMenuTree(array $data, int $parentId = 0): array + { + $tree = []; + + foreach ($data as $item) { + // 只处理非权限类型的节点 + if ($item['parent_id'] == $parentId && $item['type'] != 'permission') { + // 转换数据结构以匹配前端需要的格式 + $menuItem = [ + 'id' => $item['id'], + 'path' => $item['url'] ?? '', + 'name' => $item['name'], + 'component' => $item['url'] ?? '', + 'meta' => [ + 'title' => $item['name'], + 'icon' => $item['icon'] ?? '', + 'isHide' => !empty($item['is_hide']), + 'isHideTab' => !empty($item['is_hide_tab']), + 'keepAlive' => !empty($item['keep_alive']), + ] + ]; + + // 收集当前节点下的所有权限 + $permissions = static::collectDirectPermissions($data, $item['id']); + if (!empty($permissions)) { + $authList = []; + foreach ($permissions as $permission) { + $authList[] = [ + 'id' => $permission['id'], + 'title' => $permission['name'] ?? '', + 'authMark' => $permission['code'] ?? '', + 'selected' => isset($permission['selected']) && $permission['selected'] ? true : false + ]; + } + $menuItem['meta']['authList'] = $authList; + } + + // 将服务端额外字段放入meta中 + $extraFields = static::getExtraFields($item); + if (!empty($extraFields)) { + $menuItem['meta'] = array_merge($menuItem['meta'], $extraFields); + } + + // 递归处理子菜单 + $children = static::buildMenuTree($data, $item['id']); + if (!empty($children)) { + $menuItem['children'] = $children; + } + + $tree[] = $menuItem; + } + } + + return $tree; + } + + /** + * 使用引用方式构建前端需要的菜单树结构(性能更好) + * + * @param array $data 服务端菜单数据 + * @return array + */ + public static function buildMenuTreeWithReference(array $data): array + { + $items = []; + $tree = []; + + // 过滤出菜单类型的节点并转换数据结构 + $menuData = array_filter($data, function($item) { + return ($item['type'] ?? '') != 'permission'; + }); + + // 建立以id为索引的数组并转换数据结构 + foreach ($menuData as $item) { + $items[$item['id']] = [ + 'id' => $item['id'], + 'path' => $item['url'] ?? '', + 'name' => $item['name'], + 'component' => $item['url'] ?? '', + 'meta' => [ + 'title' => $item['name'], + 'icon' => $item['icon'] ?? '', + 'isHide' => !empty($item['is_hide']), + 'isHideTab' => !empty($item['is_hide_tab']), + 'keepAlive' => !empty($item['keep_alive']), + ] + ]; + + // 将服务端额外字段放入meta中 + $extraFields = static::getExtraFields($item); + if (!empty($extraFields)) { + $items[$item['id']]['meta'] = array_merge($items[$item['id']]['meta'], $extraFields); + } + } + + // 构建树形结构 + foreach ($menuData as $item) { + if ($item['parent_id'] == 0) { + $tree[] = &$items[$item['id']]; + } else { + if (isset($items[$item['parent_id']])) { + if (!isset($items[$item['parent_id']]['children'])) { + $items[$item['parent_id']]['children'] = []; + } + $items[$item['parent_id']]['children'][] = &$items[$item['id']]; + } + } + } + + // 为每个节点添加权限列表 + foreach ($items as &$item) { + $parentId = $item['id']; + $permissions = static::collectDirectPermissions($data, $parentId); + if (!empty($permissions)) { + $authList = []; + foreach ($permissions as $permission) { + $authList[] = [ + 'id' => $permission['id'], + 'title' => $permission['name'] ?? '', + 'authMark' => $permission['code'] ?? '' + ]; + } + $item['meta']['authList'] = $authList; + } + } + + return $tree; + } + + /** + * 收集指定节点下的直接权限项(只收集直接子节点中的权限) + * + * @param array $data 数据列表 + * @param int $parentId 父级ID + * @return array + */ + public static function collectDirectPermissions(array $data, int $parentId): array + { + $permissions = []; + + foreach ($data as $item) { + // 收集直接子节点中的权限类型 + if ($item['parent_id'] == $parentId && ($item['type'] ?? '') == 'permission') { + $permissions[] = $item; + } + } + + return $permissions; + } + + /** + * 获取需要放入meta的额外字段 + * + * @param array $item 菜单项 + * @return array + */ + public static function getExtraFields(array $item): array + { + $extraFields = []; + $standardFields = [ + 'id', 'name', 'url', 'icon', 'is_hide', 'is_hide_tab', 'keep_alive', 'level' + ]; + + foreach ($item as $key => $value) { + // 如果不是标准字段且不是auth_list,则放入extraFields + if (!in_array($key, $standardFields) && $key !== 'auth_list') { + // 转换下划线命名到驼峰命名 + $camelKey = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key)))); + $extraFields[$camelKey] = $value; + } + } + + return $extraFields; + } +} \ No newline at end of file diff --git a/app/common/utils/scaffold/Generate.php b/app/common/utils/scaffold/Generate.php index 753a9cf..eb82025 100644 --- a/app/common/utils/scaffold/Generate.php +++ b/app/common/utils/scaffold/Generate.php @@ -156,8 +156,11 @@ class Generate protected function deleteFileIfExists($path) { if (file_exists($path)) { - unlink($path); - echo "删除已存在文件: {$path} \n"; + "文件: {$path} 已存在,核对后手动删除。\n"; + return; + + // unlink($path); + // echo "删除已存在文件: {$path} \n"; } } diff --git a/app/common/utils/scaffold/templates/workOrder.stub b/app/common/utils/scaffold/templates/workOrder.stub new file mode 100644 index 0000000..c7b6ab0 --- /dev/null +++ b/app/common/utils/scaffold/templates/workOrder.stub @@ -0,0 +1,102 @@ + + + + + + 邮箱提醒 + + + + + + + + + + + + + + + +
    +

    工单提醒

    +
    +

    你好,

    +

    你有新的工单待处理。请及时查看:

    + +
      +
    • 工单编号:{{code}}
    • +
    • 工单分类:{{category}}
    • +
    • 问题描述:{{content}}
    • +
    + +

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

    + + + + +
    + + \ No newline at end of file diff --git a/app/common/validate/CorpFeishuAppValidate.php b/app/common/validate/CorpFeishuAppValidate.php new file mode 100644 index 0000000..d055d65 --- /dev/null +++ b/app/common/validate/CorpFeishuAppValidate.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/common/validate/CountryValidate.php b/app/common/validate/CountryValidate.php new file mode 100644 index 0000000..d2a413b --- /dev/null +++ b/app/common/validate/CountryValidate.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/common/validate/ResourceValidate.php b/app/common/validate/ResourceValidate.php new file mode 100644 index 0000000..ea2646e --- /dev/null +++ b/app/common/validate/ResourceValidate.php @@ -0,0 +1,29 @@ + [ + + ], + + 'update' => [ + + ] + ]; +} \ No newline at end of file diff --git a/app/common/validate/RoleValidate.php b/app/common/validate/RoleValidate.php index 372159f..dec4431 100644 --- a/app/common/validate/RoleValidate.php +++ b/app/common/validate/RoleValidate.php @@ -26,7 +26,7 @@ class RoleValidate extends Validate ]; protected $scene = [ - 'store' => ['system_id', 'name', 'desc', 'sort'], - 'update' => ['id', 'system_id', 'name', 'desc', 'sort', 'status'], + 'store' => ['name', 'desc', 'sort'], + 'update' => ['id', 'name', 'desc', 'sort', 'status'], ]; } diff --git a/app/common/validate/UserValidate.php b/app/common/validate/UserValidate.php index 7db260d..dcdaa9b 100644 --- a/app/common/validate/UserValidate.php +++ b/app/common/validate/UserValidate.php @@ -55,7 +55,7 @@ class UserValidate extends Validate 'feishu_register' => ['feishu_code'], 'upwd_login' => ['account' => 'require|checkAccount', 'password'], 'feishu_auth' => ['corp_abbr', 'system_code', 'login_type'], - 'feishu_login' => ['feishu_code'] + 'feishu_login' => ['feishu_code'], ]; /** diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index fa0fce1..e7ae182 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -75,27 +75,27 @@ class IndexController public function createResource() { $options = [ - // 'controller' => [ - // 'module' => 'inquiry', - // 'name' => 'country' - // ], + 'controller' => [ + 'module' => 'common', + 'name' => 'resources' + ], 'model' => [ 'module' => 'common', - 'name' => 'email_parsed_result' + 'name' => 'resources' ], - // 'service' => [ - // 'module' => 'inquiry', - // 'name' => 'country' - // ], - // 'logic' => [ - // 'module' => 'inquiry', - // 'name' => 'country' - // ], - // 'validate' => [ - // 'module' => 'inquiry', - // 'name' => 'country' - // ], - 'table' => 'email_parsed_result' + 'service' => [ + 'module' => 'common', + 'name' => 'resources' + ], + 'logic' => [ + 'module' => 'common', + 'name' => 'resources' + ], + 'validate' => [ + 'module' => 'common', + 'name' => 'resources' + ], + 'table' => 'resources' ]; $result = (new Generate($options))->doGenerate(); @@ -106,13 +106,21 @@ class IndexController public function test() { - $uidRotator = new \app\common\utils\RedisUidRotator('email_parsed_result_20250804'); - $uidRotator->setUids([64, 63, 83, 93, 108, 118, 131, 132, 145, 150, 143, 156, 157, 158]); + // $data = [ + // 'code' => 'GD20250703-1DC80', + // 'category' => '账号类问题', + // 'content' => '这是一条测试工单内容。' + // ]; + // \app\common\utils\email\MailSend::send('mzl@hnxinyouhe.com', '【XYH】新的工单提醒', replaceTpl($data, 'work_order')); - $assignedUid = $uidRotator->next(); + // $options = [ + // 'corp_id' => 3, + // 'user_id' => 666 + // ]; + // \Webman\RedisQueue\Redis::send('perm-agt', $options); - flg($assignedUid, false); - - return $assignedUid; + $res = Cache::delete("user_resources_74_fdesk"); + + return 22; } } \ No newline at end of file diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index d1e7cdb..3b6e8ec 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -325,6 +325,7 @@ class CustomerController extends BaseController 'lng' => Util::getParam($request, 'lng', 0), 'address' => Util::getParam($request, 'address', ''), 'sex' => Util::getParam($request, 'sex', 0), + 'obtain' => time(), ]; if (Util::isEmpty($id)) { @@ -393,13 +394,31 @@ class CustomerController extends BaseController if(empty($customer)){ return $this->error( trans('fail')); } - if($force == 'force'){ - //强制删除 - $res = $customer->forceDelete(); - }else{ - //软删除 - $res = $customer->delete(); + try { + Db::beginTransaction(); + if ($force == 'force') { + //强制删除 + $res = $customer->forceDelete(); + } else { + $customer->user_id = 0; + $customer->save(); + + //记录客户关系变化 + $his = CustomerHis::create([ + 'customer_id' => $id, + 'user_his' => $userId, + 'user_id' => 0, + ]); + + //软删除 + $res = $customer->delete(); + } + Db::commit(); + } catch (\Throwable $e) { + Db::rollback(); + return $this->error($e->getMessage()); } + if ($res) { return $this->success($res, trans('success')); } else { @@ -485,10 +504,10 @@ class CustomerController extends BaseController return $this->error(trans('customer_id').trans('not_null')); } $data = [ - 'user_id' => $request->user->uid + 'user_id' => $request->user->uid, + 'obtain' => time(), ]; - try { Db::beginTransaction(); $customer= Customer::withTrashed()->find($customerId); @@ -526,8 +545,6 @@ class CustomerController extends BaseController } } - - /** * 批量转让 * @param Request $request @@ -543,10 +560,11 @@ class CustomerController extends BaseController return $this->error( trans('user_none')); } - $query= Customer::whereIn('id',explode(',',$customerId)); + $query= Customer::withTrashed()->whereIn('id',explode(',',$customerId)); try { $customer = $query->get(); + Db::beginTransaction(); foreach ($customer as $item) { //记录客户关系变化 $his = CustomerHis::create([ @@ -561,8 +579,15 @@ class CustomerController extends BaseController $inquiryLog->save(); } } + + $item->restore(); } - $res = $query->update(['user_id' => $user->id]); + + $data = [ + 'user_id' => $user->id, + 'obtain' => time(), + ]; + $res = $query->update($data); Db::commit(); } catch (\Throwable $e) { diff --git a/app/crm/model/Customer.php b/app/crm/model/Customer.php index af5c571..326eb72 100644 --- a/app/crm/model/Customer.php +++ b/app/crm/model/Customer.php @@ -79,4 +79,31 @@ class Customer extends Model { return $this->belongsTo(User::class, 'user_id', 'id'); } + + protected static function booted() + { + static::saved(function ($customer) { + if (empty($customer->code)) { + $customer->code = self::generateCustomerCode($customer); + // 使用saveQuietly避免递归调用 + $customer->saveQuietly(); + } + }); + } + + public static function generateCustomerCode($customer) + { + // 生成唯一16位code,CM+14位 + $unique = strtoupper(substr(md5($customer->id . microtime(true) . mt_rand(1000, 9999)), 8, 6)); + $code = 'CM' . date('Ymd') .$unique; + return $code; + } + + // 静默保存方法,不触发事件 + public function saveQuietly(array $options = []) + { + return static::withoutEvents(function () use ($options) { + return $this->save($options); + }); + } } \ No newline at end of file diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 8621636..0573972 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -36,6 +36,7 @@ class CustomerService $follow = $params['follow'] ?? ''; $follow_last = $params['follow_last'] ?? ''; $tagId = $params['tag_id'] ?? []; + $countryId = $params['country_id'] ?? ''; $where = []; $user_id =$params['user_id']; @@ -49,6 +50,9 @@ class CustomerService } $where[] = ['status', 1]; + if (!empty($countryId)){ + $where[] = ['country_id', $countryId]; + } $grade = []; if (!Util::isEmpty($follow) && $follow == 0) { @@ -84,7 +88,10 @@ class CustomerService if (!Util::isEmpty($keyword)) { $query->where(function ($query) use ($keyword) { $query->where('contacts', 'like', "%{$keyword}%") - ->orWhere('phone', 'like', "%{$keyword}%"); + ->orWhere('phone', 'like', "%{$keyword}%") + ->orWhere('email', 'like', "%{$keyword}%") + ->orWhere('WhatsApp', 'like', "%{$keyword}%") + ->orWhere('code', 'like', "%{$keyword}%"); }); } if (!Util::isEmpty($grade)) { @@ -148,9 +155,16 @@ class CustomerService switch ($scene) { case 'index': $config['where']['status'] = 1; // 关键字 + if (isset($p['user_id']) && $p['user_id']) { + $config['where']['user_id'] = $p['user_id']; + } // 关键字 if (isset($p['keyword']) && $p['keyword']) { $k = '%' . $p['keyword'] . '%'; - $config['where']['contacts'] = ['like', $k]; + $config['orWhere'][] = ['contacts','like', $k]; + $config['orWhere'][] = ['phone','like', $k]; + $config['orWhere'][] = ['email','like', $k]; + $config['orWhere'][] = ['WhatsApp','like', $k]; + $config['orWhere'][] = ['code','like', $k]; } $config['order']['id'] = 'desc'; $config['dataLimit']['type'] = 'relation'; @@ -162,6 +176,11 @@ class CustomerService return $config; } + /** + * 无用线索举报 + * @param $params + * @return false + */ public function report($params) { $id = $params['id']; diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index 153941a..a3dc0e2 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -3,6 +3,7 @@ namespace app\crmAdmin\controller; use app\common\model\Corp; +use app\crm\model\Customer; use app\crmAdmin\service\CustomerService; use support\Request; @@ -133,6 +134,37 @@ class CustomerController extends BaseController } } + /** + * 移除 + * @param Request $request + * @return \support\Response + */ + public function delete(Request $request) + { + try { + $param = $request->all(); + if (empty($param['customer_id'])) { + return $this->error('customer_id'.trans('not_null')); + } + + $where = [ + 'id' => $param['customer_id'], + ]; + $customer = Customer::where($where)->withTrashed()->first(); + if(empty($customer)){ + return $this->error( trans('fail')); + } + //软删除 + $customer->status = 3; + $res = $customer->save(); + $customer->delete(); + + return $this->success($res); + } catch (\Throwable $th) { + return $this->error($th->getMessage()); + } + } + /** * 客户详情 * @param Request $request @@ -154,4 +186,25 @@ class CustomerController extends BaseController } } + /** + * 客户详情 + * @param Request $request + * @return \support\Response + */ + public function follow(Request $request) + { + try { + $param = $request->all(); + if (empty($param['id'])) { + return $this->error('id'.trans('not_null')); + } + + $result = (new CustomerService())->follow($param); + + return $this->success($result); + } 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 869982f..83ba426 100644 --- a/app/crmAdmin/logic/CustomerLogic.php +++ b/app/crmAdmin/logic/CustomerLogic.php @@ -13,6 +13,10 @@ class CustomerLogic $customer->status = $status; $res = $customer->save(); + if($status == 1){ + $customer->restore(); + } + return $res; } @@ -20,7 +24,9 @@ class CustomerLogic { $customer = Customer::withTrashed()->find($id); //强制删除 - $res = $customer->forceDelete(); +// $res = $customer->forceDelete(); + $customer->status = 3; + $res = $customer->save(); return $res; } } \ No newline at end of file diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 6a68ee7..074f341 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -4,6 +4,7 @@ namespace app\crmAdmin\service; use app\common\model\InquiryLog; use app\common\model\User; +use app\common\service\OssService; use app\crm\model\CustomerHis; use app\crmAdmin\logic\CustomerLogic; use app\crm\model\CarType; @@ -104,16 +105,22 @@ class CustomerService if (!Util::isEmpty($keyword)) { $query->where(function ($query) use ($keyword) { $query->where('contacts', 'like', "%{$keyword}%") - ->orWhere('phone', 'like', "%{$keyword}%"); + ->orWhere('phone', 'like', "%{$keyword}%") + ->orWhere('email', 'like', "%{$keyword}%") + ->orWhere('WhatsApp', 'like', "%{$keyword}%") + ->orWhere('code', 'like', "%{$keyword}%"); }); } if (!Util::isEmpty($grade)) { $query->whereIn('grade', $grade); } - if ($recycle == 'recycle' || $scene == 'recycle' || $seas == 'seas' || $scene == 'seas' || $scene == 'audit') { + if ($recycle == 'recycle' || $scene == 'recycle' || $scene == 'audit') { $query->onlyTrashed(); } + if ($seas == 'seas' || $scene == 'seas') { + $query->withTrashed(); + } if (!$export) { $customer = $query->orderBy('id', 'desc')->paginate($perPage, ['*'], 'page', $page); @@ -124,9 +131,10 @@ class CustomerService if (!$export) { 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() - strtotime($item['deleted_at']); + $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']); @@ -315,7 +323,42 @@ class CustomerService } } } - $res = $query->update(['user_id' => $userId]); + $data = [ + 'user_id' => $userId, + 'obtain' => time(), + ]; + $res = $query->update($data); + + Db::commit(); + return $res; + } catch (\Throwable $e) { + Db::rollback(); + throw $e; + } + } + + /** + * @param $params + * @return bool + */ + public function delete($params) + { + try { + Db::beginTransaction(); + $customerId = $params['customer_id']; + + $query= Customer::whereIn('id',explode(',',$customerId)); + $customer = $query->get(); + + foreach ($customer as $item) { + //记录客户关系变化 + $his = CustomerHis::create([ + 'customer_id' => $item->id, + 'user_his' => $item->user_id, + 'user_id' => 0, + ]); + } + $res = $query->update(['user_id' => 0]); Db::commit(); return $res; @@ -394,4 +437,19 @@ class CustomerService return $customer; } + + public function follow($params) + { + $id = $params['id']; + $follow = Follow:: + where('customer_id', $id) + ->get(); + + $ossservice = new OssService(); + foreach ($follow as $item) { + $item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture); + } + + return $follow; + } } \ No newline at end of file diff --git a/app/functions.php b/app/functions.php index 59fdd24..299bad4 100644 --- a/app/functions.php +++ b/app/functions.php @@ -158,9 +158,10 @@ if (!function_exists('sendFeishuTextMessage')) { * 替换模板 */ if (!function_exists('replaceTpl')) { - function replaceTpl(array $data = [], string $templatePath = 'common/utils/scaffold/templates/Email.stub') + function replaceTpl(array $data = [], string $tplKey = 'email') { - if (!$data || !$templatePath) return ''; + if (!$data || !$tplKey) return ''; + $templatePath = tplUrl($tplKey); $templatePath = app_path($templatePath); $content = file_get_contents($templatePath); foreach ($data as $key => $value) { @@ -170,6 +171,20 @@ if (!function_exists('replaceTpl')) { } } +/** + * 模板路径 + */ +if (!function_exists('tplUrl')) { + function tplUrl(string $tplKey = '') + { + $urlArray = [ + 'email' => 'common/utils/scaffold/templates/Email.stub', + 'work_order' => 'common/utils/scaffold/templates/workOrder.stub' + ]; + return $urlArray[$tplKey]; + } +} + /** * 替换模板 */ diff --git a/app/inquiry/controller/StatisticsController.php b/app/inquiry/controller/StatisticsController.php index 0e37719..8412715 100644 --- a/app/inquiry/controller/StatisticsController.php +++ b/app/inquiry/controller/StatisticsController.php @@ -101,7 +101,7 @@ class StatisticsController extends BaseController { $list = InquiryLog::with(["recipientInfo"]) ->where("recipient", ">", 0) - ->whereNotIn('recipient', [1,5,10,11,13,15,16,17,19,74,75,78,141,147]) + ->whereNotIn('recipient', [1,5,10,11,13,155,16,17,19,74,75,78,141,147]) ->select('recipient', Db::raw('COUNT(*) as totals')) ->groupBy('recipient') ->get(); diff --git a/app/queue/redis/InquiryToCrm.php b/app/queue/redis/InquiryToCrm.php index 8e1ae51..7bec9ca 100644 --- a/app/queue/redis/InquiryToCrm.php +++ b/app/queue/redis/InquiryToCrm.php @@ -60,6 +60,7 @@ class InquiryToCrm implements Consumer $crmCustomer->contacts = $info->contacts; $crmCustomer->desc_collect = $info->content; $crmCustomer->enter_user_id = $info->enter_user_id; + $crmCustomer->obtain = time(); // 修改同步CRM状态 $info->sync_crm = 1; // 保存 diff --git a/app/queue/redis/PermAgt.php b/app/queue/redis/PermAgt.php new file mode 100644 index 0000000..42a4898 --- /dev/null +++ b/app/queue/redis/PermAgt.php @@ -0,0 +1,95 @@ + $userId, + 'role_id' => 1 + ], + [ + 'user_id' => $userId, + 'role_id' => 2 + ], + ]; + $systems = [ + [ + 'user_id' => $userId, + 'system_id' => 1 + ], + [ + 'user_id' => $userId, + 'system_id' => 2 + ], + [ + 'user_id' => $userId, + 'system_id' => 3 + ], + ]; + } else { + $roles = [ + 'user_id' => $userId, + 'role_id' => 2 + ]; + $systems = [ + [ + 'user_id' => $userId, + 'system_id' => 2 + ], + [ + 'user_id' => $userId, + 'system_id' => 3 + ], + ]; + } + + Db::table('user_roles')->insert($roles); + Db::table('user_systems')->insert($systems); + return true; + } catch (\Throwable $th) { + throw new BusinessException($th->getFile()."|".$th->getLine()."|".$th->getMessage()); + } + } + + // 消费失败回调 + /* + $package = [ + 'id' => 1357277951, // 消息ID + 'time' => 1709170510, // 消息时间 + 'delay' => 0, // 延迟时间 + 'attempts' => 2, // 消费次数 + 'queue' => 'send-mail', // 队列名 + 'data' => ['to' => 'tom@gmail.com', 'content' => 'hello'], // 消息内容 + 'max_attempts' => 5, // 最大重试次数 + 'error' => '错误信息' // 错误信息 + ] + */ + public function onConsumeFailure(\Throwable $e, $package) + { + echo "consume failure\n"; + echo $e->getMessage() . "\n"; + // 无需反序列化 + var_export($package); + } +} \ No newline at end of file diff --git a/config/route.php b/config/route.php index 0c928eb..9c33c32 100644 --- a/config/route.php +++ b/config/route.php @@ -52,12 +52,17 @@ Route::group('/common', function () { Route::group('/user', function () { Route::any('/info', [app\common\controller\UserController::class, 'info']); Route::any('/get', [app\common\controller\UserController::class, 'getUser']); + Route::any('/team', [app\common\controller\UserController::class, 'team']); + Route::any('/resign', [app\common\controller\UserController::class, 'resignMember']); }); Route::group('/preset', function () { Route::any('/corps', [app\common\controller\PresetController::class, 'corps']); Route::any('/feishu/app', [app\common\controller\PresetController::class, 'feishuApp']); Route::any('/systems', [app\common\controller\PresetController::class, 'systems']); + Route::any('/roles', [app\common\controller\PresetController::class, 'roles']); + Route::any('/cache/clear', [app\common\controller\PresetController::class, 'cacheClear']); + Route::any('/menus', [app\common\controller\PresetController::class, 'menus']); }); }); @@ -70,13 +75,7 @@ Route::group('/admin', function () { Route::any('/store', [app\admin\controller\RoleController::class, 'store']); Route::any('/update', [app\admin\controller\RoleController::class, 'update']); Route::any('/destroy', [app\admin\controller\RoleController::class, 'destroy']); - }); - - // 用户 - Route::group('/user', function () { - Route::any('/list', [app\admin\controller\UserController::class, 'index']); - Route::any('/show', [app\admin\controller\UserController::class, 'show']); - Route::any('/update', [app\admin\controller\UserController::class, 'update']); + Route::any('/menu/resource', [app\admin\controller\RoleController::class, 'menuResource']); }); // 公司 @@ -88,6 +87,46 @@ Route::group('/admin', function () { Route::any('/destroy', [app\admin\controller\CorpController::class, 'destroy']); }); + // 系统 + Route::group('/systems', function () { + Route::any('/list', [app\admin\controller\SystemsController::class, 'index']); + Route::any('/show', [app\admin\controller\SystemsController::class, 'show']); + Route::any('/store', [app\admin\controller\SystemsController::class, 'store']); + Route::any('/update', [app\admin\controller\SystemsController::class, 'update']); + Route::any('/destroy', [app\admin\controller\SystemsController::class, 'destroy']); + }); + + // 飞书应用 + Route::group('/corp/feishu', function () { + Route::any('/list', [app\admin\controller\CorpFeishuAppController::class, 'index']); + Route::any('/show', [app\admin\controller\CorpFeishuAppController::class, 'show']); + Route::any('/store', [app\admin\controller\CorpFeishuAppController::class, 'store']); + Route::any('/update', [app\admin\controller\CorpFeishuAppController::class, 'update']); + Route::any('/destroy', [app\admin\controller\CorpFeishuAppController::class, 'destroy']); + }); + + // 资源 + Route::group('/resources', function () { + Route::any('/list/tree', [app\common\controller\ResourceController::class, 'listTree']); + Route::any('/show', [app\common\controller\ResourceController::class, 'show']); + Route::any('/store', [app\common\controller\ResourceController::class, 'store']); + Route::any('/update', [app\common\controller\ResourceController::class, 'update']); + Route::any('/destroy', [app\common\controller\ResourceController::class, 'destroy']); + Route::any('/list/menu', [app\common\controller\ResourceController::class, 'menuList']); + Route::any('/list/menu/tree', [app\common\controller\ResourceController::class, 'menuTreeList']); + }); + + // 用户 + Route::group('/user', function () { + Route::any('/list', [app\admin\controller\UserController::class, 'index']); + Route::any('/show', [app\admin\controller\UserController::class, 'show']); + Route::any('/update', [app\admin\controller\UserController::class, 'update']); + Route::any('/edit', [app\admin\controller\UserController::class, 'edit']); + Route::any('/authorize', [app\admin\controller\UserController::class, 'authorize']); + Route::any('/set/resources', [app\admin\controller\UserController::class, 'updateResources']); + Route::any('/update/password', [app\admin\controller\UserController::class, 'savePassword']); + }); + // 询单 Route::group('/inquiry', function () { Route::any('/list', [app\inquiry\controller\InquiryLogController::class, 'index']); @@ -117,6 +156,9 @@ Route::group('/admin', function () { Route::any('/audit', [app\crmAdmin\controller\CustomerController::class, 'audit']); 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('/cede', [app\crm\controller\CustomerController::class, 'cede']); + Route::any('/follow', [app\crmAdmin\controller\CustomerController::class, 'follow']); }); }); }); @@ -177,7 +219,7 @@ Route::group('/crm', function () { Route::any('/upload/image', [app\common\controller\UploadController::class, 'uploadImage']); - Route::any('/user/edit', [app\common\controller\UserController::class, 'edit']); - Route::any('/user/savePassword', [app\common\controller\UserController::class, 'savePassword']); + Route::any('/user/edit', [app\common\controller\UserController::class, 'edit']); + Route::any('/user/savePassword', [app\common\controller\UserController::class, 'savePassword']); }); From 646b39dec8eb2fa54a7de10703cf90a100ef21fc Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 14 Aug 2025 20:59:20 +0800 Subject: [PATCH 03/45] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E5=8E=9F=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/model/CustomerAudit.php | 49 +++++++++++++++++++ app/crm/controller/CustomerController.php | 3 ++ app/crm/service/CustomerService.php | 8 +++ .../controller/CustomerController.php | 2 +- app/crmAdmin/service/CustomerService.php | 2 + 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 app/common/model/CustomerAudit.php 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 @@ +error(trans('id_empty')); } + if (Util::isEmpty($param['remark'])) { + return $this->error('举报理由不能为空'); + } $param['user_id'] = $request->user->uid; $param['corp_abbr'] = $request->basic_data['corp_abbr']; diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 0573972..3baa4ae 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -3,6 +3,7 @@ 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; @@ -195,6 +196,13 @@ class CustomerService return false; } + CustomerAudit::create([ + 'customer_id' => $id, + 'report_user_id' => $userId, + 'remark' => $params['remark'], + 'img' => implode(',', $params['img']), + ]); + CustomerHis::create([ 'customer_id' => $id, 'user_his' => $userId, diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index a3dc0e2..a214a2c 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -85,7 +85,7 @@ class CustomerController extends BaseController } /** - * 客户列表 + * 审核客户 * @param Request $request * @return \support\Response */ diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 074f341..09faa5a 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; @@ -139,6 +140,7 @@ class CustomerService 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'); + $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(['user_his']); } } } From 1fa2342007fdb7f009d5041b408dff3bee97a645 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Sat, 16 Aug 2025 16:12:06 +0800 Subject: [PATCH 04/45] =?UTF-8?q?=E5=88=86=E9=85=8D=E7=A6=BB=E8=81=8C?= =?UTF-8?q?=E5=91=98=E5=B7=A5=E5=AE=A2=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CustomerController.php | 27 ++++++++++ app/crmAdmin/service/CustomerService.php | 51 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index a214a2c..c6279e7 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -207,4 +207,31 @@ class CustomerController extends BaseController } } + /** + * 离职员工客户分配 + * @param Request $request + * @return \support\Response + */ + public function allocation(Request $request) + { + try { + $param = $request->all(); + if (empty($param['id'])) { + return $this->error('id'.trans('not_null')); + } + 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); + } catch (\Throwable $th) { + return $this->error($th->getMessage()); + } + } + } \ No newline at end of file diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 09faa5a..256451b 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -21,6 +21,7 @@ use PhpOffice\PhpSpreadsheet\Style\Alignment; use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Style\Fill; use support\Db; +use support\Log; class CustomerService { @@ -454,4 +455,54 @@ class CustomerService return $follow; } + + /** + * 离职员工客户分配 + * @param $params + * @return Follow[]|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Collection[] + */ + public function allocation($params) + { + $id = $params['id']; + $corpId = $params['corp_id']; + $userId = $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($userIds)) { + log::info('匹配到离职用户数:' . count($resignUerIds) .' '. implode(',',$userNames)); + } + + $customers = Customer::whereIn('user_id', $resignUerIds) + ->orderBy('id', 'asc') + ->get(['id','user_id']); + + if (!$customers || count($customers) === 0) { + $output->writeln('未找到相关的 crm_customer 记录。'); + log::info('未找到相关的离职员工客户记录。' ; + return []; + } + + $follow = Follow:: + where('customer_id', $id) + ->get(); + + $ossservice = new OssService(); + foreach ($follow as $item) { + $item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture); + } + + return $follow; + } } \ No newline at end of file From 79cd5336c5f3de23875b4e0c2326e11f96fe0eb5 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 10:27:24 +0800 Subject: [PATCH 05/45] =?UTF-8?q?=E6=97=A0=E6=95=88=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E4=B8=BE=E6=8A=A5=E5=9B=BE=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/model/CustomerAudit.php | 49 +++++++++++++++++++ app/crm/controller/CustomerController.php | 3 ++ app/crm/service/CustomerService.php | 9 ++++ .../controller/CustomerController.php | 2 +- app/crmAdmin/logic/CustomerLogic.php | 1 + app/crmAdmin/service/CustomerService.php | 10 ++++ 6 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 app/common/model/CustomerAudit.php 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 @@ +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']; diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 0573972..b7654f0 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -3,6 +3,7 @@ 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; @@ -195,6 +196,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, diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index a3dc0e2..a214a2c 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -85,7 +85,7 @@ class CustomerController extends BaseController } /** - * 客户列表 + * 审核客户 * @param Request $request * @return \support\Response */ 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..a79481a 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; @@ -139,6 +140,10 @@ class CustomerService 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'); + $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); + if (!empty($item['audit'])&&!empty($item['audit']['img'])) { + $item['audit']['img'] = explode(',', $item['audit']['img']); + } } } } @@ -287,9 +292,14 @@ class CustomerService $id = $params['id']; $logic = new CustomerLogic(); + $audit = CustomerAudit::where('customer_id', $id)->orderBy('id', 'desc')->first(); if ($params['scene'] == 'delete') { + $audit->status = 3; + $audit->save(); return $logic->forceDelete($params['id']); } else { + $audit->status = 2; + $audit->save(); return $logic->status($params['id'], 1); } } From 5642089c62a163707a369706d0c7460fd6ee4943 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 10:38:41 +0800 Subject: [PATCH 06/45] =?UTF-8?q?=E5=8F=91=E9=80=81=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/ConversationService.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index ea52002..fef9eab 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -59,7 +59,9 @@ class ConversationService 'reply' => '', ]; if (empty($conversation)) { - $email = 'app@hnxinyouhe.com'; + //$email = 'app@hnxinyouhe.com'; //公共邮箱 + $email = 'tuotuo@hnxinyouhe.com'; //范彩凤 + $email = 'beimanr@hnxinyouhe.com'; //范彩凤 }else{ $tiket = (new TicketLogic)->find($conversation['ticket_id']); if($data['user_id'] != $tiket['user_id']){ From ad619362b6feea30498cdd226d1b808771a232da Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 11:20:35 +0800 Subject: [PATCH 07/45] =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/logic/CategorieLogic.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/ticket/logic/CategorieLogic.php b/app/ticket/logic/CategorieLogic.php index f9f1014..7eefaed 100644 --- a/app/ticket/logic/CategorieLogic.php +++ b/app/ticket/logic/CategorieLogic.php @@ -25,9 +25,9 @@ class CategorieLogic public function find($id) { - return Categorie::with('translation') - ->where('status',1) - ->where('locale', locale()) + return Categorie::with(['translation' => function ($query) { + $query->where('locale', locale()); + }])->where('status', 1) ->find($id); } From c32e768e411679d101936bbaaddedb2d552d8586 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 11:32:33 +0800 Subject: [PATCH 08/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E5=9B=9E=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/ConversationService.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index fef9eab..fdd963b 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -49,11 +49,12 @@ class ConversationService } $conversation = (new ConversationLogic())->firstByTicket($data['ticket_id']); - $categorie= (new CategorieLogic())->find($data['categorie_id']); + $ticket = (new TicketLogic())->find($data['ticket_id']); + $categorie= (new CategorieLogic())->find($ticket['categorie_id']); $categorieName = isset($categorie['translation']) ? $categorie['translation']['name'] : ''; $notice = [ - 'code' => $data['code'], + 'code' => $ticket['code'], 'category' => $categorieName, 'content' => $data['content'], 'reply' => '', From d8b80aefeca274f2e35c820c5e19a565fc459d8c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 13:57:46 +0800 Subject: [PATCH 09/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E9=82=AE=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/ConversationService.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index fdd963b..4417284 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -59,21 +59,21 @@ class ConversationService 'content' => $data['content'], 'reply' => '', ]; + //$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱 + $emailDefault = 'tuotuo@hnxinyouhe.com'; //范彩凤 if (empty($conversation)) { - //$email = 'app@hnxinyouhe.com'; //公共邮箱 - $email = 'tuotuo@hnxinyouhe.com'; //范彩凤 - $email = 'beimanr@hnxinyouhe.com'; //范彩凤 + $email = $emailDefault; }else{ $tiket = (new TicketLogic)->find($conversation['ticket_id']); if($data['user_id'] != $tiket['user_id']){ $email = User::find($tiket['user_id'])->value('email'); }else{ - $conversationLast = Conversation::where('user_id', '=', $conversation['user_id']) - ->where('ticket_id', '=', $conversation['ticket_id']) - ->where('user_id', '!=', $conversation['user_id']) + $conversationLast = Conversation::where('ticket_id', '=', $conversation['ticket_id']) + ->where('user_id', '!=', $data['user_id']) ->orderBy('id', 'desc') ->first(); - $email = User::find($conversationLast['user_id'])->value('email','app@hnxinyouhe.com'); + + $email = (!empty($conversationLast['user_id']))?User::find($conversationLast['user_id'])->value('email',$emailDefault):$emailDefault; } $notice['content'] = $tiket['content']; $notice['reply'] = '
  • 最新回复:' . $data['content'] . '
  • '; From 7aa717b93e8697a1645bbe4ac373551d7cb4811a Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 15:14:30 +0800 Subject: [PATCH 10/45] =?UTF-8?q?=E7=A6=BB=E8=81=8C=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CustomerController.php | 2 +- app/crmAdmin/service/CustomerService.php | 36 +++++++++++-------- config/route.php | 1 + 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index c6279e7..2584003 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -228,7 +228,7 @@ class CustomerController extends BaseController $result = (new CustomerService())->allocation($param); - return $this->success($result); + return $this->success(); } catch (\Throwable $th) { return $this->error($th->getMessage()); } diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 256451b..757a2a2 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -21,6 +21,7 @@ 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 @@ -481,28 +482,33 @@ class CustomerService $userNames[] = $row->name; } if (empty($userIds)) { - log::info('匹配到离职用户数:' . count($resignUerIds) .' '. implode(',',$userNames)); + log::info('未匹配到离职用户'); + throw new BusinessException('未找到离职员工相关的客户记录', 500); } + log::info('匹配到离职用户数:' . count($resignUerIds) .' '. implode(',',$userNames)); - $customers = Customer::whereIn('user_id', $resignUerIds) + $customerCount = Customer::whereIn('user_id', $resignUerIds) ->orderBy('id', 'asc') - ->get(['id','user_id']); + ->count(); - if (!$customers || count($customers) === 0) { - $output->writeln('未找到相关的 crm_customer 记录。'); - log::info('未找到相关的离职员工客户记录。' ; - return []; + if ($customerCount === 0) { + log::info('未找到离职员工相关的客户记录。'); + throw new BusinessException('未找到离职员工相关的客户记录', 500); } - $follow = Follow:: - where('customer_id', $id) - ->get(); + // 初始化 UID 轮询器 + $uidRotator = new \app\common\utils\RedisUidRotator('allocation_customer_user'); + $uidRotator->setUids($params, false); - $ossservice = new OssService(); - foreach ($follow as $item) { - $item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture); - } + Customer::chunk(200, function ($customers, $uidRotator) { + foreach ($customers as $customer) { + // 获取下一个分配的UID + $newUserId = $uidRotator->next(); + $customer->user_id = $newUserId; + } + }); - return $follow; + + return true; } } \ No newline at end of file diff --git a/config/route.php b/config/route.php index 9c33c32..e4702a3 100644 --- a/config/route.php +++ b/config/route.php @@ -159,6 +159,7 @@ Route::group('/admin', function () { Route::any('/delete', [app\crmAdmin\controller\CustomerController::class, 'delete']); 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']); }); }); }); From 66890fa893591b4471dfd94c3a5450678be2642c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 16:08:44 +0800 Subject: [PATCH 11/45] =?UTF-8?q?=E9=82=AE=E4=BB=B6=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ConversationController.php | 18 +++++++ app/ticket/service/ConversationService.php | 52 +++++++++++++++++-- config/route.php | 1 + 3 files changed, 67 insertions(+), 4 deletions(-) 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/service/ConversationService.php b/app/ticket/service/ConversationService.php index 4417284..e80704a 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -64,19 +64,25 @@ class ConversationService if (empty($conversation)) { $email = $emailDefault; }else{ - $tiket = (new TicketLogic)->find($conversation['ticket_id']); + $tiket = (new TicketLogic())->find($conversation['ticket_id']); if($data['user_id'] != $tiket['user_id']){ - $email = User::find($tiket['user_id'])->value('email'); + $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::find($conversationLast['user_id'])->value('email',$emailDefault):$emailDefault; + $email = (!empty($conversationLast['user_id']))?User::where('id',$conversationLast['user_id'])->value('email',$emailDefault):$emailDefault; } $notice['content'] = $tiket['content']; - $notice['reply'] = '
  • 最新回复:' . $data['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 . '
  • '; } \app\common\utils\email\MailSend::send($email, '【XYH】新的工单提醒', replaceTpl($notice, 'work_order')); @@ -89,6 +95,44 @@ class ConversationService } } + 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 = 'tuotuo@hnxinyouhe.com'; //范彩凤 + 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/config/route.php b/config/route.php index 27ba099..ddae5f9 100644 --- a/config/route.php +++ b/config/route.php @@ -168,6 +168,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']); From 3ba830259a0b9312617a16e7829032a97df1f09c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 16:54:24 +0800 Subject: [PATCH 12/45] =?UTF-8?q?=E5=88=86=E9=85=8D=E7=A6=BB=E8=81=8C?= =?UTF-8?q?=E5=AE=A2=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CustomerController.php | 5 +---- app/crmAdmin/service/CustomerService.php | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index 2584003..2f3ba2e 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -216,9 +216,6 @@ class CustomerController extends BaseController { try { $param = $request->all(); - if (empty($param['id'])) { - return $this->error('id'.trans('not_null')); - } if (empty($param['corp_id'])) { return $this->error('corp_id'.trans('not_null')); } @@ -228,7 +225,7 @@ class CustomerController extends BaseController $result = (new CustomerService())->allocation($param); - return $this->success(); + return $this->success($result,'成功分配'.$result['userCount'].'位离职用户的'.$result['customerCount'].'位客户'); } catch (\Throwable $th) { return $this->error($th->getMessage()); } diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 757a2a2..7357efb 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -460,13 +460,12 @@ class CustomerService /** * 离职员工客户分配 * @param $params - * @return Follow[]|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Collection[] + * @return string[] */ public function allocation($params) { - $id = $params['id']; $corpId = $params['corp_id']; - $userId = $params['user_id']; + $userId = explode(',', $params['user_id']); log::info('开始分配离职员工客户,corp_id:'.$corpId.' 被分配员工'. implode(',', $userId)); @@ -481,9 +480,9 @@ class CustomerService $resignUerIds[] = (int)$row->id; $userNames[] = $row->name; } - if (empty($userIds)) { + if (empty($userResign)) { log::info('未匹配到离职用户'); - throw new BusinessException('未找到离职员工相关的客户记录', 500); + throw new BusinessException('未匹配到离职用户', 500); } log::info('匹配到离职用户数:' . count($resignUerIds) .' '. implode(',',$userNames)); @@ -498,17 +497,21 @@ class CustomerService // 初始化 UID 轮询器 $uidRotator = new \app\common\utils\RedisUidRotator('allocation_customer_user'); - $uidRotator->setUids($params, false); + $uidRotator->setUids($userId, false); - Customer::chunk(200, function ($customers, $uidRotator) { + 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 true; + return [ + 'userCount' => count($resignUerIds), + 'customerCount' => $customerCount, + ]; } } \ No newline at end of file From a4fd38ac2391f0c2ab00011019d9c4fb27f3371f Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Mon, 18 Aug 2025 18:06:36 +0800 Subject: [PATCH 13/45] =?UTF-8?q?=E4=B8=BE=E6=8A=A5=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E8=A1=A5=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index a79481a..5d3a816 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -144,6 +144,11 @@ class CustomerService if (!empty($item['audit'])&&!empty($item['audit']['img'])) { $item['audit']['img'] = explode(',', $item['audit']['img']); } + + $ossservice = new OssService(); + foreach ($item['audit']['img'] as $k => $img) { + $item['audit']['img'][$k] = $ossservice->generatePrivateUrl($img); + } } } } From 0df8e3d2ebf00f290e8e694909830c0142644633 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 19 Aug 2025 13:47:31 +0800 Subject: [PATCH 14/45] =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=B3=BB=E7=BB=9F=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/service/ResourceService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/common/service/ResourceService.php b/app/common/service/ResourceService.php index ad3f85b..c1654a5 100644 --- a/app/common/service/ResourceService.php +++ b/app/common/service/ResourceService.php @@ -53,6 +53,7 @@ class ResourceService $config['order']['id'] = 'asc'; break; case 'menuTreeList': + $config['where']['system_id'] = ['in', [0, $p['system_id']]]; $config['where']['status'] = 1; $config['order']['sort'] = 'asc'; $config['order']['id'] = 'asc'; From dac360ec65d9afd5d52504feab19daa5fb075d04 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 19 Aug 2025 13:54:19 +0800 Subject: [PATCH 15/45] Merge branch 'develop' --- app/common/model/CustomerAudit.php | 49 ++++++++++++ app/crm/controller/CustomerController.php | 3 + app/crm/service/CustomerService.php | 9 +++ .../controller/CustomerController.php | 26 ++++++- app/crmAdmin/logic/CustomerLogic.php | 1 + app/crmAdmin/service/CustomerService.php | 75 +++++++++++++++++++ config/route.php | 1 + 7 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 app/common/model/CustomerAudit.php 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 @@ +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']; diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 0573972..b7654f0 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -3,6 +3,7 @@ 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; @@ -195,6 +196,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, diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index a3dc0e2..2f3ba2e 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -85,7 +85,7 @@ class CustomerController extends BaseController } /** - * 客户列表 + * 审核客户 * @param Request $request * @return \support\Response */ @@ -207,4 +207,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..2ded7cb 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 { @@ -139,6 +142,15 @@ class CustomerService 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'); + $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); + if (!empty($item['audit'])&&!empty($item['audit']['img'])) { + $item['audit']['img'] = explode(',', $item['audit']['img']); + } + + $ossservice = new OssService(); + foreach ($item['audit']['img'] as $k => $img) { + $item['audit']['img'][$k] = $ossservice->generatePrivateUrl($img); + } } } } @@ -287,9 +299,14 @@ class CustomerService $id = $params['id']; $logic = new CustomerLogic(); + $audit = CustomerAudit::where('customer_id', $id)->orderBy('id', 'desc')->first(); if ($params['scene'] == 'delete') { + $audit->status = 3; + $audit->save(); return $logic->forceDelete($params['id']); } else { + $audit->status = 2; + $audit->save(); return $logic->status($params['id'], 1); } } @@ -452,4 +469,62 @@ class CustomerService 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/config/route.php b/config/route.php index fd117b2..2abd88a 100644 --- a/config/route.php +++ b/config/route.php @@ -159,6 +159,7 @@ Route::group('/admin', function () { Route::any('/delete', [app\crmAdmin\controller\CustomerController::class, 'delete']); 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']); }); }); }); From 1152c1a7f95d2005f29d24bf27e2ba99bd5b6efd Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 19 Aug 2025 14:17:34 +0800 Subject: [PATCH 16/45] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 5d3a816..4d3f6b1 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -140,7 +140,8 @@ class CustomerService 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'); - $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); + $audit = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); + $item['audit'] = $audit?$audit->toArray():''; if (!empty($item['audit'])&&!empty($item['audit']['img'])) { $item['audit']['img'] = explode(',', $item['audit']['img']); } From e1796100d6664c76a7a89866929e0ee2568a854f Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 19 Aug 2025 14:24:01 +0800 Subject: [PATCH 17/45] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 4d3f6b1..21d543a 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -140,15 +140,14 @@ class CustomerService 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(); - $item['audit'] = $audit?$audit->toArray():''; + $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); if (!empty($item['audit'])&&!empty($item['audit']['img'])) { $item['audit']['img'] = explode(',', $item['audit']['img']); - } - $ossservice = new OssService(); - foreach ($item['audit']['img'] as $k => $img) { - $item['audit']['img'][$k] = $ossservice->generatePrivateUrl($img); + $ossservice = new OssService(); + foreach ($item['audit']['img'] as $k => $img) { + $item['audit']['img'][$k] = $ossservice->generatePrivateUrl($img); + } } } } From db1ac82412a7e0ebc3eed9114e6d37f619b5d47c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 19 Aug 2025 14:26:26 +0800 Subject: [PATCH 18/45] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 21d543a..8dbd794 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -142,6 +142,7 @@ class CustomerService $item['user_name'] = empty($customerHis['user_his']) ? '' : User::where('id',$customerHis['user_his'])->value('name'); $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); if (!empty($item['audit'])&&!empty($item['audit']['img'])) { + $item['audit'] = $item['audit']?$item['audit']->toArray():''; $item['audit']['img'] = explode(',', $item['audit']['img']); $ossservice = new OssService(); From 960ba9346c493579b694f6645036e1ad18098657 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 19 Aug 2025 14:36:52 +0800 Subject: [PATCH 19/45] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 8dbd794..ba74841 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -140,16 +140,17 @@ class CustomerService 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'); - $item['audit'] = CustomerAudit::where('customer_id', $item->id)->orderBy('id', 'desc')->first(); - if (!empty($item['audit'])&&!empty($item['audit']['img'])) { - $item['audit'] = $item['audit']?$item['audit']->toArray():''; - $item['audit']['img'] = explode(',', $item['audit']['img']); + $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 ($item['audit']['img'] as $k => $img) { - $item['audit']['img'][$k] = $ossservice->generatePrivateUrl($img); + foreach ($audit['img'] as $k => $img) { + $audit['img'][$k] = $ossservice->generatePrivateUrl($img); } } + $item['audit'] = $audit; } } } From e647fde12866b2925d94e9506e8dc2b23a84448c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 19 Aug 2025 15:56:53 +0800 Subject: [PATCH 20/45] =?UTF-8?q?=E5=AE=A1=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index ba74841..4859e7d 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -301,12 +301,16 @@ class CustomerService $logic = new CustomerLogic(); $audit = CustomerAudit::where('customer_id', $id)->orderBy('id', 'desc')->first(); if ($params['scene'] == 'delete') { - $audit->status = 3; - $audit->save(); + if(!empty($audit)){ + $audit->status = 3; + $audit->save(); + } return $logic->forceDelete($params['id']); } else { - $audit->status = 2; - $audit->save(); + if(!empty($audit)){ + $audit->status = 2; + $audit->save(); + } return $logic->status($params['id'], 1); } } From 220f1df6ca798a637c0d12bc0544826ac079fe98 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 19 Aug 2025 16:36:36 +0800 Subject: [PATCH 21/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E7=A7=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/controller/CustomerController.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index 2f3ba2e..900046d 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -147,15 +147,18 @@ class CustomerController extends BaseController return $this->error('customer_id'.trans('not_null')); } - $where = [ - 'id' => $param['customer_id'], - ]; - $customer = Customer::where($where)->withTrashed()->first(); + $customer_id = explode(',', $param['customer_id']); + $customer = Customer::whereIn('id',$customer_id)->withTrashed()->first(); if(empty($customer)){ return $this->error( trans('fail')); } - //软删除 - $customer->status = 3; + if($param['scene'] == 'list'){ //管理端客户列表移除 + $customer->status = 4; + + }else{ //公海软删除 + $customer->status = 3; + + } $res = $customer->save(); $customer->delete(); From e7cf1dce94954b2b75c23c01aa9dccc0f9c36eb4 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 09:40:52 +0800 Subject: [PATCH 22/45] =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/service/UserService.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/admin/service/UserService.php b/app/admin/service/UserService.php index 4d23710..3354e88 100644 --- a/app/admin/service/UserService.php +++ b/app/admin/service/UserService.php @@ -75,6 +75,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']; } From 2d2e30faa98b58891c2bdf6e4b2d99c1ce5a1996 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 11:29:05 +0800 Subject: [PATCH 23/45] =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/CustomerService.php | 2 +- app/crm/utils/Util.php | 8 +++++++- app/ticket/service/ConversationService.php | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index b7654f0..ef5aa71 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -256,7 +256,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); 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/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index e80704a..22da6fb 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -60,7 +60,7 @@ class ConversationService 'reply' => '', ]; //$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱 - $emailDefault = 'tuotuo@hnxinyouhe.com'; //范彩凤 + $emailDefault = 'support@hnxinyouhe.com'; //范彩凤 if (empty($conversation)) { $email = $emailDefault; }else{ @@ -108,7 +108,7 @@ class ConversationService 'reply' => '', ]; //$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱 - $emailDefault = 'tuotuo@hnxinyouhe.com'; //范彩凤 + $emailDefault = 'support@hnxinyouhe.com'; //范彩凤 if (empty($conversation)) { $email = $emailDefault; }else{ From 9f8bab618d96fbda81dc112e4a07642398e51445 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 11:37:41 +0800 Subject: [PATCH 24/45] =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index a3ee935..ce4dda1 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -427,7 +427,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); From c7c25381ccdd0ba0e4669e7c35f1adea441af7d3 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 11:41:15 +0800 Subject: [PATCH 25/45] =?UTF-8?q?=E6=97=B6=E9=97=B4=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crmAdmin/service/CustomerService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index ce4dda1..038a5e0 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -135,7 +135,6 @@ 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'])); } From bba9c294f4b5750a6680091ca4e044803b7bf10e Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 13:37:25 +0800 Subject: [PATCH 26/45] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 1 + app/ticket/model/Conversation.php | 6 +----- app/ticket/service/ConversationService.php | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index f391abd..7d05d44 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) { 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/service/ConversationService.php b/app/ticket/service/ConversationService.php index 22da6fb..05158c8 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -35,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; From dbebaa9805ac12d691aa6bc6618576a22f0f5164 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 14:20:54 +0800 Subject: [PATCH 27/45] =?UTF-8?q?=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 7d05d44..a2296cd 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -163,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], ]; From 3c731594d2dafef67ea4fdcf836b20cea88d9ccd Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 14:38:20 +0800 Subject: [PATCH 28/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/model/Ticket.php | 7 ------- app/ticket/service/TicketService.php | 2 ++ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php index cf71b2a..737482c 100644 --- a/app/ticket/model/Ticket.php +++ b/app/ticket/model/Ticket.php @@ -51,13 +51,6 @@ class Ticket extends Model 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 = [ 'code', 'categorie_id', diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index d12c4e7..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); From 5cede502e38b7d2a3657d030cf67a2b8ec547de2 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 14:40:19 +0800 Subject: [PATCH 29/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/TicketService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index ce772df..4be052f 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -33,8 +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']); + $res[$k]['created_at'] = date('Y-m-d H:i:s', strtotime($v['created_at'])); + $res[$k]['updated_at'] = date('Y-m-d H:i:s', strtotime($v['updated_at'])); } unset($v); unset($attachments); From f83824c46255c70680ffbf441ec118998094eef8 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 15:16:16 +0800 Subject: [PATCH 30/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/model/Ticket.php | 8 ++++++++ app/ticket/service/TicketService.php | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php index 737482c..41b3794 100644 --- a/app/ticket/model/Ticket.php +++ b/app/ticket/model/Ticket.php @@ -51,6 +51,14 @@ class Ticket extends Model protected $dateFormat = 'U'; + /** + * 指定哪些字段自动转换为 Carbon 实例 + */ + public function getDates() + { + return []; + } + protected $fillable = [ 'code', 'categorie_id', diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index 4be052f..ce772df 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -33,8 +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', strtotime($v['created_at'])); - $res[$k]['updated_at'] = date('Y-m-d H:i:s', strtotime($v['updated_at'])); + $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); From 08a7a10392e91a774581f9fe66527f73eec0ab88 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 15:24:36 +0800 Subject: [PATCH 31/45] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/model/Ticket.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/ticket/model/Ticket.php b/app/ticket/model/Ticket.php index 41b3794..d1bbe9e 100644 --- a/app/ticket/model/Ticket.php +++ b/app/ticket/model/Ticket.php @@ -47,10 +47,27 @@ class Ticket extends Model * * @var bool */ - public $timestamps = true; + public $timestamps = false; protected $dateFormat = 'U'; + /** + * 在保存时手动设置时间戳 + */ + protected static function boot() + { + parent::boot(); + + static::creating(function ($model) { + $model->created_at = time(); + $model->updated_at = time(); + }); + + static::updating(function ($model) { + $model->updated_at = time(); + }); + } + /** * 指定哪些字段自动转换为 Carbon 实例 */ From 691cb5421abac61b1ee082cef31317b428691fea Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 17:52:44 +0800 Subject: [PATCH 32/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/CustomerService.php | 37 +++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index ef5aa71..64e0ce8 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -10,12 +10,16 @@ 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 { @@ -37,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']; @@ -72,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 里任意一个标签的客户 @@ -115,7 +121,34 @@ 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->orderBy('crm_customer.follow_next', 'asc'); + $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'){ From 8b61923692119f673dfb28a0102a7fd6c62f486c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 17:57:50 +0800 Subject: [PATCH 33/45] =?UTF-8?q?=E5=85=AC=E5=8F=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index a2296cd..3d03c9e 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -330,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)) { From 19082ea6c82fbb1c5dd0001086190833dc4c311b Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 18:19:41 +0800 Subject: [PATCH 34/45] =?UTF-8?q?=E6=8E=92=E5=BA=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/CustomerService.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 64e0ce8..9cc5ca1 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -141,7 +141,6 @@ class CustomerService }elseif ($sort == 'follow_last') { $query = $query->orderBy('crm_customer.follow_last', 'desc'); }elseif ($sort == 'follow_next') { - $query = $query->orderBy('crm_customer.follow_next', 'asc'); $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'); From ba69b2c2c0d46b9d6eb423a1a95ab3db607e2739 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Wed, 20 Aug 2025 18:27:38 +0800 Subject: [PATCH 35/45] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/CustomerService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 9cc5ca1..a3559d5 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -313,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(); From bf0e385a592a4204817ef13317be3ba2b843a592 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 21 Aug 2025 10:12:06 +0800 Subject: [PATCH 36/45] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=82=AE=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/ConversationService.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/ticket/service/ConversationService.php b/app/ticket/service/ConversationService.php index 05158c8..ea97cef 100644 --- a/app/ticket/service/ConversationService.php +++ b/app/ticket/service/ConversationService.php @@ -62,7 +62,8 @@ class ConversationService 'reply' => '', ]; //$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱 - $emailDefault = 'support@hnxinyouhe.com'; //范彩凤 + //$emailDefault = 'support@hnxinyouhe.com'; //公共邮箱 + $emailDefault = env('TICKET_EMAIL_DEFAULT'); if (empty($conversation)) { $email = $emailDefault; }else{ @@ -86,7 +87,9 @@ class ConversationService $notice['reply'] = '
  • 最新回复:' . $content . '
  • '; } - \app\common\utils\email\MailSend::send($email, '【XYH】新的工单提醒', replaceTpl($notice, 'work_order')); + if(!empty($emailDefault)){ + \app\common\utils\email\MailSend::send($email, '【XYH】新的工单提醒', replaceTpl($notice, 'work_order')); + } unset($data['categorie_id']); unset($data['code']); @@ -110,7 +113,8 @@ class ConversationService 'reply' => '', ]; //$emailDefault = 'app@hnxinyouhe.com'; //公共邮箱 - $emailDefault = 'support@hnxinyouhe.com'; //范彩凤 + //$emailDefault = 'support@hnxinyouhe.com'; //公共邮箱 + $emailDefault = env('ticket_email_default'); if (empty($conversation)) { $email = $emailDefault; }else{ From 59151cf04eb8fa128d56743bd1f55bae6244cd1c Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 21 Aug 2025 11:07:41 +0800 Subject: [PATCH 37/45] =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E5=91=98=E8=87=AA?= =?UTF-8?q?=E8=A1=8C=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 3d03c9e..ab72713 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -388,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, 'force',''); $userId = $request->user->uid; $where = [ @@ -401,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(); @@ -414,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(); From 60dcc3399f7beec425191a01a427a8e91feabce9 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 21 Aug 2025 14:02:28 +0800 Subject: [PATCH 38/45] =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/service/UserService.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/admin/service/UserService.php b/app/admin/service/UserService.php index 3354e88..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); From fad96708eab6437df1a5853226d5473e6ac41a0a Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 21 Aug 2025 14:11:34 +0800 Subject: [PATCH 39/45] =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E5=91=98=E5=88=A0?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index ab72713..e51b83f 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -388,7 +388,7 @@ class CustomerController extends BaseController public function delete(Request $request) { $id = Util::getParam($request, 'id'); - $scene = Util::getParam($request, 'force',''); + $scene = Util::getParam($request, 'scene',''); $userId = $request->user->uid; $where = [ From d41fc55e617d1486748f03d76649ebaab16fdd29 Mon Sep 17 00:00:00 2001 From: mzl Date: Thu, 21 Aug 2025 14:31:37 +0800 Subject: [PATCH 40/45] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=B0=E5=91=98?= =?UTF-8?q?=E5=B7=A5=E5=9C=A8=E6=B2=A1=E6=9C=89=E4=BC=81=E4=B8=9A=E9=82=AE?= =?UTF-8?q?=E7=AE=B1=E6=97=B6=EF=BC=8C=E4=B8=8D=E8=83=BD=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/logic/AuthLogic.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) 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(); From 61bf0fadf3ac1b56e4652e6f583d22f80b13ef70 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 21 Aug 2025 17:25:37 +0800 Subject: [PATCH 41/45] =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=AB=AF=E5=9B=9E?= =?UTF-8?q?=E6=94=B6=E7=AB=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CustomerController.php | 43 ++++++++++++++----- app/crmAdmin/service/CustomerService.php | 16 +++++-- config/route.php | 1 + 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index 900046d..535726f 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; @@ -148,19 +149,18 @@ class CustomerController extends BaseController } $customer_id = explode(',', $param['customer_id']); - $customer = Customer::whereIn('id',$customer_id)->withTrashed()->first(); - if(empty($customer)){ + $query = Customer::whereIn('id',$customer_id)->withTrashed(); + if(!$query->exists()){ return $this->error( trans('fail')); } - if($param['scene'] == 'list'){ //管理端客户列表移除 - $customer->status = 4; - - }else{ //公海软删除 - $customer->status = 3; - + $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()]); } - $res = $customer->save(); - $customer->delete(); return $this->success($res); } catch (\Throwable $th) { @@ -168,6 +168,29 @@ class CustomerController extends BaseController } } + + /** + * 客户恢复 + * @param Request $request + * @return \support\Response + */ + public function restore(Request $request) + { + $id = $request->input('id', ''); + if (Util::isEmpty($id)) { + return $this->error(trans('id_empty')); + } + $id = explode(',', $id); + $query = Customer::whereIn('id', $id); + //$res = $query->restore(); + $res = $query->update(['status' => 1, 'user_id' => 0]); + if($res){ + return $this->success($res, trans('success')); + }else{ + return $this->error(trans('fail')); + } + } + /** * 客户详情 * @param Request $request diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 038a5e0..546bc7c 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -51,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]; } @@ -121,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) { @@ -153,6 +155,14 @@ class CustomerService } $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; + } } } unset($item); diff --git a/config/route.php b/config/route.php index 2abd88a..ec46cc4 100644 --- a/config/route.php +++ b/config/route.php @@ -157,6 +157,7 @@ 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']); From b713ddb722157bcba7a8806e84aaed4a52c6e3a5 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Thu, 21 Aug 2025 17:50:42 +0800 Subject: [PATCH 42/45] =?UTF-8?q?=E5=9B=9E=E6=94=B6=E7=AB=99=E6=81=A2?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CustomerController.php | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/app/crmAdmin/controller/CustomerController.php b/app/crmAdmin/controller/CustomerController.php index 535726f..c68bd18 100644 --- a/app/crmAdmin/controller/CustomerController.php +++ b/app/crmAdmin/controller/CustomerController.php @@ -176,18 +176,23 @@ class CustomerController extends BaseController */ public function restore(Request $request) { - $id = $request->input('id', ''); - if (Util::isEmpty($id)) { - return $this->error(trans('id_empty')); - } - $id = explode(',', $id); - $query = Customer::whereIn('id', $id); - //$res = $query->restore(); - $res = $query->update(['status' => 1, 'user_id' => 0]); - if($res){ + 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')); - }else{ - return $this->error(trans('fail')); + } catch (\Throwable $th) { + return $this->error($th->getMessage()); } } From c6908e57ccf2b561195b8e48a36d7cd6e1f775eb Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Fri, 22 Aug 2025 13:59:39 +0800 Subject: [PATCH 43/45] =?UTF-8?q?=E8=B7=9F=E8=BF=9B=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/model/Follow.php | 10 +++------- app/crm/service/FollowService.php | 2 ++ app/crmAdmin/service/CustomerService.php | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/crm/model/Follow.php b/app/crm/model/Follow.php index 778b669..bc284c6 100644 --- a/app/crm/model/Follow.php +++ b/app/crm/model/Follow.php @@ -38,13 +38,9 @@ class Follow extends Model */ 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', // 指定序列化格式 + 'follow_time' => 'timestamp', // 指定序列化格式 + 'updated_at' => 'timestamp', // 指定序列化格式 + 'created_at' => 'timestamp', // 指定序列化格式 ]; } \ No newline at end of file diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php index e8ce0f7..e300f11 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -59,6 +59,8 @@ 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 = Util::formatDate($follow); return $follow; } diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 038a5e0..f8589de 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -469,6 +469,7 @@ class CustomerService $ossservice = new OssService(); foreach ($follow as $item) { + $item = Util::formatDate($item,['created_at','updated_at','follow_time']); $item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture); } From cb7d5078fe7c7d8c001ca991ef84e2e10266eb36 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Fri, 22 Aug 2025 14:31:33 +0800 Subject: [PATCH 44/45] =?UTF-8?q?=E8=B7=9F=E8=BF=9B=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/model/Follow.php | 23 +++++++++++++++++------ app/crm/service/FollowService.php | 5 ++++- app/crmAdmin/service/CustomerService.php | 3 +++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/crm/model/Follow.php b/app/crm/model/Follow.php index bc284c6..f57ef18 100644 --- a/app/crm/model/Follow.php +++ b/app/crm/model/Follow.php @@ -36,11 +36,22 @@ class Follow extends Model * * @var bool */ - public $timestamps = true; + public $timestamps = false; - protected $casts = [ - 'follow_time' => 'timestamp', // 指定序列化格式 - 'updated_at' => 'timestamp', // 指定序列化格式 - 'created_at' => 'timestamp', // 指定序列化格式 - ]; + /** + * 在保存时手动设置时间戳 + */ + protected static function boot() + { + parent::boot(); + + 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/FollowService.php b/app/crm/service/FollowService.php index e300f11..e8ec322 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -60,7 +60,10 @@ class FollowService } $follow['picture_full'] = $oss_picture; - $follow = Util::formatDate($follow,['created_at','updated_at','follow_time']); +// $follow = Util::formatDate($follow,['created_at','updated_at','follow_time']); + $follow['follow_time'] = empty($follow['follow_time'])?'':date('Y-m-d H:i:s', $follow['follow_time']); + $follow['created_at'] = empty($follow['created_at'])?'':date('Y-m-d H:i:s', $follow['created_at']); + $follow['updated_at'] = empty($follow['updated_at'])?'':date('Y-m-d H:i:s', $follow['updated_at']);; // $follow = Util::formatDate($follow); return $follow; } diff --git a/app/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index f8589de..20f4137 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -470,6 +470,9 @@ 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'])?'':date('Y-m-d H:i:s', $item['follow_time']); + $item['created_at'] = empty($item['created_at'])?'':date('Y-m-d H:i:s', $item['created_at']); + $item['updated_at'] = empty($item['updated_at'])?'':date('Y-m-d H:i:s', $item['updated_at']);; $item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture); } From 96475892e9dd469603fc2ad4c79add18b8c2c5ff Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Fri, 22 Aug 2025 14:49:10 +0800 Subject: [PATCH 45/45] =?UTF-8?q?=E8=B7=9F=E8=BF=9B=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/FollowService.php | 6 ++---- app/crmAdmin/service/CustomerService.php | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php index e8ec322..a433692 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -60,10 +60,8 @@ class FollowService } $follow['picture_full'] = $oss_picture; -// $follow = Util::formatDate($follow,['created_at','updated_at','follow_time']); - $follow['follow_time'] = empty($follow['follow_time'])?'':date('Y-m-d H:i:s', $follow['follow_time']); - $follow['created_at'] = empty($follow['created_at'])?'':date('Y-m-d H:i:s', $follow['created_at']); - $follow['updated_at'] = empty($follow['updated_at'])?'':date('Y-m-d H:i:s', $follow['updated_at']);; + $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/crmAdmin/service/CustomerService.php b/app/crmAdmin/service/CustomerService.php index 20f4137..ad51d80 100644 --- a/app/crmAdmin/service/CustomerService.php +++ b/app/crmAdmin/service/CustomerService.php @@ -470,9 +470,7 @@ 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'])?'':date('Y-m-d H:i:s', $item['follow_time']); - $item['created_at'] = empty($item['created_at'])?'':date('Y-m-d H:i:s', $item['created_at']); - $item['updated_at'] = empty($item['updated_at'])?'':date('Y-m-d H:i:s', $item['updated_at']);; + $item['follow_time'] = empty($item['follow_time'])?'':$item['follow_time']; $item['picture_full'] = empty($item->picture)?'':$ossservice->generatePrivateUrl($item->picture); }