ensureTable(); $companyId = $this->getUserInfo('companyId'); $kefuId = $this->getUserInfo('id'); // 仅返回 enabled 的库(存客宝下发);无分配 → 回退读存客宝项目知识库(REQ-TKB-133-C) $rows = Db::name('kb_touchkebao_config') ->where('companyId', $companyId) ->where('enabled', 1) ->where('kefuId', 0) // 项目级开放 ->select(); $list = []; $defaultKbId = null; foreach ($rows as $r) { $list[] = [ 'id' => (int)$r['kbId'], 'name' => $r['kbName'], 'isDefault' => (bool)$r['isDefault'], ]; if ($r['isDefault']) { $defaultKbId = (int)$r['kbId']; } } if (empty($list)) { $fallback = $this->fallbackKnowledgeFromWorkspace($companyId); $list = $fallback['list']; $defaultKbId = $fallback['defaultKbId']; } // 客服个人当前选择(覆盖默认,须在已开放范围内) $currentKbId = $defaultKbId; $myCurrent = Db::name('kb_touchkebao_config') ->where('companyId', $companyId) ->where('kefuId', $kefuId) ->value('currentKbId'); if ($myCurrent && in_array((int)$myCurrent, array_column($list, 'id'))) { $currentKbId = (int)$myCurrent; } return ResponseHelper::success([ 'defaultKbId' => $defaultKbId, 'currentKbId' => $currentKbId, 'list' => $list, ]); } /** * 客服在已分配范围内切换默认库 * POST /v1/kefu/ai/knowledge-base/select */ public function selectKnowledgeBase() { $this->ensureTable(); $companyId = $this->getUserInfo('companyId'); $kefuId = $this->getUserInfo('id'); $kbId = (int)$this->request->param('kbId', 0); if (!$kbId) { return ResponseHelper::error('kbId 缺失', 400); } // 校验是否在已开放范围内 $allowed = Db::name('kb_touchkebao_config') ->where('companyId', $companyId) ->where('enabled', 1) ->where('kbId', $kbId) ->count(); if (!$allowed) { return ResponseHelper::error('该知识库未对触客宝开放', 403); } $exist = Db::name('kb_touchkebao_config') ->where('companyId', $companyId) ->where('kefuId', $kefuId) ->find(); if ($exist) { Db::name('kb_touchkebao_config')->where('id', $exist['id']) ->update(['currentKbId' => $kbId, 'updateTime' => time()]); } else { Db::name('kb_touchkebao_config')->insert([ 'companyId' => $companyId, 'kefuId' => $kefuId, 'currentKbId' => $kbId, 'enabled' => 0, 'updateTime' => time(), ]); } return ResponseHelper::success(['currentKbId' => $kbId], '已切换'); } /** * REQ-TKB-133-C:本地分配表为空时,聚合存客宝 AiKnowledgeTouchkebao 配置 + 项目知识库 * * @return array{list:array,defaultKbId:?int} */ private function fallbackKnowledgeFromWorkspace(int $companyId): array { $kbRows = AiKnowledgeBaseType::where([ ['isDel', '=', 0], ['status', '=', 1], ])->where(function ($q) use ($companyId) { $q->where('companyId', $companyId)->whereOr('companyId', 0); })->field('id,name,companyId') ->order('companyId desc,id desc') ->select(); if (empty($kbRows)) { return ['list' => [], 'defaultKbId' => null]; } $cfgRows = Db::name('kb_touchkebao_config') ->where('companyId', $companyId) ->where('kefuId', 0) ->select(); $cfgMap = []; $defaultKbId = null; foreach ($cfgRows ?: [] as $c) { $cfgMap[(int)$c['kbId']] = $c; if (!empty($c['isDefault'])) { $defaultKbId = (int)$c['kbId']; } } $list = []; $now = time(); foreach ($kbRows as $kb) { $kbId = (int)$kb['id']; $cfg = $cfgMap[$kbId] ?? null; $enabled = $cfg ? (bool)$cfg['enabled'] : ((int)$kb['companyId'] === $companyId); if (!$enabled) { continue; } $isDefault = $cfg ? (bool)$cfg['isDefault'] : false; $list[] = [ 'id' => $kbId, 'name' => (string)($kb['name'] ?: ''), 'isDefault' => $isDefault, ]; if ($isDefault) { $defaultKbId = $kbId; } } // 仍无默认:优先项目库首条,其次系统库 if ($defaultKbId === null && !empty($list)) { $defaultKbId = (int)$list[0]['id']; $list[0]['isDefault'] = true; } // 懒同步写入分配表,便于后续 select 校验 if (!empty($list)) { foreach ($list as $item) { $exist = Db::name('kb_touchkebao_config') ->where('companyId', $companyId) ->where('kefuId', 0) ->where('kbId', $item['id']) ->find(); if ($exist) { continue; } Db::name('kb_touchkebao_config')->insert([ 'companyId' => $companyId, 'kbId' => $item['id'], 'kbName' => $item['name'], 'isDefault' => $item['isDefault'] ? 1 : 0, 'kefuId' => 0, 'currentKbId' => 0, 'enabled' => 1, 'updateTime' => $now, ]); } } return ['list' => $list, 'defaultKbId' => $defaultKbId]; } }