diff --git a/app/admin/controller/Ticket.php b/app/admin/controller/Ticket.php index 8812e0e..2db0055 100644 --- a/app/admin/controller/Ticket.php +++ b/app/admin/controller/Ticket.php @@ -8,6 +8,8 @@ use app\common\model\Tickets; use app\common\service\TicketNotifier; use app\common\service\TicketService; use think\facade\Session; +use app\common\service\TicketScope; + class Ticket extends BaseController { @@ -15,7 +17,7 @@ class Ticket extends BaseController /** * 查询工单 */ - public function ticketsFind(TicketService $ticketService) + public function fetchTickets(TicketService $ticketService) { // 在控制器明确接收参数 $params = [ @@ -32,7 +34,11 @@ class Ticket extends BaseController $limit = min(max(($params['limit'] ?? 20), 1), 100); $order = strtolower($params['sortOrder'] ?? 'desc') === 'asc' ? 'asc' : 'desc'; - $result = $ticketService->queryTickets($params, $page, $limit, $order); + try { + $result = $ticketService->queryTickets($params, $page, $limit, $order, TicketScope::admin()); + } catch (\Exception $e) { + return $this->error($e->getMessage()); + } return $this->success('查询成功', $result); } @@ -47,13 +53,13 @@ class Ticket extends BaseController try { $result = $ticketService->createTicket($data); - return $this->success('创建成功', $result); } catch (\Exception $e) { if ($e->getCode() === 409) { return $this->error($e->getMessage(), ['confirm' => true], 409); } return $this->error($e->getMessage()); } + return $this->success('创建成功', $result); } @@ -70,10 +76,11 @@ class Ticket extends BaseController try { $result = $ticketService->updateTicket($id, $data, $allowFields, $adminId, true); - return $this->success('更新成功', $result); } catch (\Exception $e) { return $this->error($e->getMessage()); } + + return $this->success('更新成功', $result); } diff --git a/app/admin/service/AccountService.php b/app/admin/service/AccountService.php index 9dadd0d..071fc88 100644 --- a/app/admin/service/AccountService.php +++ b/app/admin/service/AccountService.php @@ -12,15 +12,20 @@ class AccountService { $users = UserModel::with('company')->select(); return $users->map(function ($user) { + $companyName = $user->role === 'client' && (bool) $user->can_view_all_tickets + ? '全部客户' + : ($user->company->company_name ?? ''); + return [ 'id' => $user->id, 'company' => [ 'id' => $user->company_id, - 'company_name' => $user->company->company_name + 'company_name' => $companyName ], 'username' => $user->username, 'real_name' => $user->real_name, 'role' => $user->role, + 'can_view_all_tickets' => (bool) $user->can_view_all_tickets, 'status' => $user->status, ]; })->toArray(); @@ -40,19 +45,34 @@ class AccountService throw new \Exception('用户名已存在'); } + $role = $data['role'] ?? 'user'; + $companyId = (int) ($data['company_id'] ?? 0); + $canViewAllTickets = $role === 'client' && !empty($data['can_view_all_tickets']); + + // 系统中只允许存在一个可查看全部工单的客户汇总账号。 + if ($canViewAllTickets) { + $allAccessClient = UserModel::where('role', 'client') + ->where('can_view_all_tickets', 1) + ->find(); + if ($allAccessClient) { + throw new \Exception('已存在可查看全部工单的客户账号'); + } + } + $insertData = [ - 'company_id' => $data['company_id'] ?? 0, + 'company_id' => $companyId, 'username' => $data['username'], 'real_name' => $data['real_name'] ?? $data['username'], 'password' => password_hash('123456', PASSWORD_DEFAULT), - 'role' => $data['role'] ?? 'user', + 'role' => $role, + 'can_view_all_tickets' => $canViewAllTickets ? 1 : 0, 'status' => 1, ]; $user = UserModel::create($insertData); /** @var \think\Model $user */ - return $user->visible(['id', 'username', 'real_name', 'role', 'status'])->toArray(); + return $user->visible(['id', 'username', 'real_name', 'role', 'can_view_all_tickets', 'status'])->toArray(); } /* 更新用户状态 */ diff --git a/app/common/model/Tickets.php b/app/common/model/Tickets.php index 4d7e8ca..3a5a71c 100644 --- a/app/common/model/Tickets.php +++ b/app/common/model/Tickets.php @@ -16,7 +16,6 @@ class Tickets extends Model protected $createTime = 'create_time'; protected $updateTime = 'update_time'; - # 定义字段类型 protected $type = [ 'id' => 'integer', @@ -30,10 +29,17 @@ class Tickets extends Model 'remark' => 'string', 'lock_time' => 'integer', 'create_time' => 'integer', - 'update_time' => 'integer', + 'update_time' => 'integer', ]; + # 定义状态常量 + const STATUS_UNASSIGNED = 0; + const STATUS_PROCESSING = 1; + const STATUS_COMPLETED = 2; + const STATUS_CLOSED = 3; + + /* 时间戳获取器 */ diff --git a/app/common/model/User.php b/app/common/model/User.php index 9bf8e52..23bb0a4 100644 --- a/app/common/model/User.php +++ b/app/common/model/User.php @@ -12,6 +12,10 @@ class User extends Model { protected $table = 'users'; + protected $type = [ + 'can_view_all_tickets' => 'boolean', + ]; + public function company(){ return $this->belongsTo(Companys::class,'company_id','id'); } diff --git a/app/common/service/AuthService.php b/app/common/service/AuthService.php index f360bba..9f1ab5a 100644 --- a/app/common/service/AuthService.php +++ b/app/common/service/AuthService.php @@ -18,7 +18,6 @@ class AuthService ->find(); - if (!$user || !password_verify($password, $user['password'])) { throw new \Exception('用户名或密码错误'); } @@ -31,13 +30,16 @@ class AuthService $userInfo = [ 'id' => $user['id'], // 用户ID 'company_id' => $user['company_id'], // 所属公司ID - 'company_name' => $user['company']['company_name'], // 所属公司名称 + 'company_name' => $user['role'] === 'client' && (bool) $user['can_view_all_tickets'] + ? '全部客户' + : ($user['company']['company_name'] ?? ''), // 所属公司名称 'username' => $user['username'], 'role' => $user['role'], + 'can_view_all_tickets' => (bool) $user['can_view_all_tickets'], ]; Session::set('user_info', $userInfo); - return $userInfo; + return $userInfo; // 为了方便前端展示用户信息 } } diff --git a/app/common/service/TicketScope.php b/app/common/service/TicketScope.php new file mode 100644 index 0000000..0974e11 --- /dev/null +++ b/app/common/service/TicketScope.php @@ -0,0 +1,35 @@ +applyScope($query, $scope); + $equalFilters = ['operator_id', 'user_id', 'status']; foreach ($equalFilters as $field) { if (isset($params[$field]) && $params[$field] !== '') { @@ -56,6 +62,21 @@ class TicketService } + private function applyScope($query, TicketScope $scope): void + { + match ($scope->type) { + 'admin' => null, + 'staff' => $query->where(fn($q) => $q + ->where('status', Tickets::STATUS_UNASSIGNED) + ->where('user_id', $scope->staffId)), + }; + } + + + + + + /** * 创建工单业务逻辑 * @param array $data 工单数据 diff --git a/app/index/controller/ClientTicket.php b/app/index/controller/ClientTicket.php index e943d8a..061493d 100644 --- a/app/index/controller/ClientTicket.php +++ b/app/index/controller/ClientTicket.php @@ -13,9 +13,11 @@ class ClientTicket extends BaseController */ public function getClientTickets(ClientTicketService $ClientTicketService) { - $clientCompanyId = Session::get('user_info.company_id'); // 获取当前登录客户ID + $clientCompanyId = (int) Session::get('user_info.company_id'); // 获取当前登录客户ID + $canViewAll = Session::get('user_info.role') === 'client' + && (bool) Session::get('user_info.can_view_all_tickets'); try { - $tickets = $ClientTicketService->getClientTickets($clientCompanyId); + $tickets = $ClientTicketService->getClientTickets($clientCompanyId, $canViewAll); return $this->success('获取成功', $tickets); } catch (\Exception $e) { return $this->error($e->getMessage()); diff --git a/app/index/service/ClientTicketService.php b/app/index/service/ClientTicketService.php index ec066f6..30ea330 100644 --- a/app/index/service/ClientTicketService.php +++ b/app/index/service/ClientTicketService.php @@ -8,17 +8,20 @@ use app\common\model\Tickets; class ClientTicketService { /* 获取客户关联工单 */ - public function getClientTickets($clientCompanyId) + public function getClientTickets(int $clientCompanyId, bool $canViewAll = false) { - # 查询当前登录用户所对应的公司的工单 - $tickets = Tickets::where('company_id', $clientCompanyId)->select(); + // 普通客户仅查询所属公司的工单;唯一的汇总客户账号可查看全部。 + $query = Tickets::whereIn('status', [0, 1, 2]); + if (!$canViewAll) { + $query->where('company_id', $clientCompanyId); + } + + $tickets = $query->select(); $newList = []; foreach ($tickets as $ticket) { - if (in_array($ticket->status, [0, 1, 2])) { - $ticket->visible(['id', 'website', 'datanum', 'progress', 'status']); - $newList[] = $ticket->toArray(); - } + $ticket->visible(['id', 'website', 'datanum', 'progress', 'status']); + $newList[] = $ticket->toArray(); } return $newList; diff --git a/app/staff/controller/Ticket.php b/app/staff/controller/Ticket.php new file mode 100644 index 0000000..d1abbe5 --- /dev/null +++ b/app/staff/controller/Ticket.php @@ -0,0 +1,64 @@ + $this->request->param('page', 1, 'intval'), + "limit" => $this->request->param('limit', 20, 'intval'), + "operator_id" => $this->request->param('operator_id', null), + "status" => $this->request->param('status', null), + "searchKeyword" => $this->request->param('search', null), + "sortOrder" => $this->request->param('sort_order', 'desc'), + ]; + + $staffId = (int) Session::get('user_info.id'); // 若没有,则为0 + if ($staffId <= 0) { + return $this->error('无法获取当前员工信息'); + } + + $page = max(($params['page'] ?? 1), 1); + $limit = min(max(($params['limit'] ?? 20), 1), 100); + $order = strtolower($params['sortOrder'] ?? 'desc') === 'asc' ? 'asc' : 'desc'; + + try { + $result = $TicketService->queryTickets($params, $page, $limit, $order, TicketScope::staff($staffId)); + } catch (\Exception $e) { + return $this->error($e->getMessage()); + } + + return $this->success('查询成功', $result); + } + + + + + + /** + * 更新工单(员工调用) + */ + public function updateTicket(TicketService $ticketService, $id) + { + + $isUser = Session::get('user_info.role') === 'user'; + $data = $this->request->post(); + + $allowFields = ['datanum', 'progress', 'status', 'remark', 'lock_time', 'user_id']; + + try { + $result = $ticketService->updateTicket($id, $data, $allowFields, $isUser, false); + return $this->success('更新成功', $result); + } catch (\Exception $e) { + return $this->error($e->getMessage()); + } + } +} diff --git a/database/migrations/20260819_add_can_view_all_tickets_to_users.sql b/database/migrations/20260819_add_can_view_all_tickets_to_users.sql new file mode 100644 index 0000000..b530a11 --- /dev/null +++ b/database/migrations/20260819_add_can_view_all_tickets_to_users.sql @@ -0,0 +1,6 @@ +-- Up: 为客户汇总账号增加显式的全量工单查看标记。 +ALTER TABLE `users` + ADD COLUMN `can_view_all_tickets` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `role`; + +-- Rollback(需要回滚时单独执行): +-- ALTER TABLE `users` DROP COLUMN `can_view_all_tickets`;