request->param('force', 0)) === 1; $delay = max(0, intval($this->request->param('delay', 1))); $svc = new ExpertFieldAiService(); $started = $svc->startLinkChain($force, $delay); return jsonSuccess([ 'started' => $started, 'queue' => ExpertFieldAiService::QUEUE_NAME, 'force' => $force, 'msg' => $started ? 'link chain enqueued' : 'no pending experts', ]); } /** * 同步关联单个 expert */ public function linkOne() { $expertId = intval($this->request->param('expert_id', 0)); $force = intval($this->request->param('force', 0)) === 1; if ($expertId <= 0) { return jsonError('expert_id required'); } $svc = new ExpertFieldAiService(); $result = $svc->linkFromUser($expertId, $force); if (empty($result['ok'])) { return jsonError(isset($result['error']) ? $result['error'] : 'failed'); } return jsonSuccess($result); } /** * 同步批量关联 * expert_ids: 逗号分隔,或传 limit 扫描待处理前 N 条 */ public function linkBatch() { $force = intval($this->request->param('force', 0)) === 1; $idsRaw = trim((string)$this->request->param('expert_ids', '')); $limit = min(max(intval($this->request->param('limit', 0)), 0), 200); $ids = []; if ($idsRaw !== '') { $ids = array_filter(array_map('intval', explode(',', $idsRaw))); } elseif ($limit > 0) { $ids = Db::name('expert') ->where('state', '<>', 5) ->where(function ($q) { $q->where('field_ai_status', ExpertFieldAiService::STATUS_PENDING) ->whereOr('field_ai_status', ExpertFieldAiService::STATUS_FAILED); }) ->order('expert_id asc') ->limit($limit) ->column('expert_id'); } if (empty($ids)) { return jsonError('expert_ids 或 limit 必填'); } $svc = new ExpertFieldAiService(); $result = $svc->batchLinkFromUser($ids, $force); return jsonSuccess($result); } /** * user 更新 field_ai 后,同步到同邮箱 expert */ public function syncByUser() { $userId = intval($this->request->param('user_id', 0)); $force = intval($this->request->param('force', 0)) === 1; if ($userId <= 0) { return jsonError('user_id required'); } $svc = new ExpertFieldAiService(); $result = $svc->syncExpertsByUserId($userId, $force); if (empty($result['ok'])) { return jsonError(isset($result['error']) ? $result['error'] : 'failed'); } return jsonSuccess($result); } /** * 预览是否可关联 */ public function preview() { $expertId = intval($this->request->param('expert_id', 0)); if ($expertId <= 0) { return jsonError('expert_id required'); } $svc = new ExpertFieldAiService(); $result = $svc->previewLink($expertId); if (empty($result['ok'])) { return jsonError(isset($result['error']) ? $result['error'] : 'failed'); } $result['field_ai_status_text'] = $svc->statusLabel(intval($result['expert_field_ai_status'])); return jsonSuccess($result); } /** * 统计 field_ai 覆盖 */ public function statistics() { $total = Db::name('expert')->where('state', '<>', 5)->count(); $done = Db::name('expert')->where('state', '<>', 5)->where('field_ai_status', ExpertFieldAiService::STATUS_DONE)->count(); $userLink = Db::name('expert') ->where('state', '<>', 5) ->where('field_ai_source', ExpertFieldAiService::SOURCE_USER_LINK) ->count(); $noUserLink = Db::name('expert') ->where('state', '<>', 5) ->where('field_ai_status', ExpertFieldAiService::STATUS_NO_USER_LINK) ->count(); $pending = Db::name('expert') ->where('state', '<>', 5) ->where('field_ai_status', ExpertFieldAiService::STATUS_PENDING) ->count(); return jsonSuccess([ 'total' => $total, 'done' => $done, 'user_link' => $userLink, 'no_user_link' => $noUserLink, 'pending' => $pending, 'coverage_rate' => $total > 0 ? round($done / $total * 100, 2) . '%' : '0%', ]); } }