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);
}