| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385 |
- <?php
- namespace App\Services;
- use Illuminate\Support\Facades\Http;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Cache;
- /**
- * 知识点掌握情况服务
- *
- * 提供:
- * 1. 获取学生知识点掌握情况统计
- * 2. 获取知识点图谱数据(考试快照)
- * 3. 获取知识点图谱快照列表
- */
- class KnowledgeMasteryService
- {
- protected string $learningAnalyticsBase;
- protected string $knowledgeServiceBase;
- protected int $timeout;
- public function __construct(?string $learningAnalyticsBase = null, ?string $knowledgeServiceBase = null, ?int $timeout = null)
- {
- $this->learningAnalyticsBase = rtrim(
- $learningAnalyticsBase
- ?: config('services.learning_analytics.url', env('LEARNING_ANALYTICS_API_BASE', 'http://localhost:5016')),
- '/'
- );
- $this->knowledgeServiceBase = rtrim(
- $knowledgeServiceBase
- ?: config('services.knowledge_service.url', env('KNOWLEDGE_SERVICE_API_BASE', 'http://localhost:5011')),
- '/'
- );
- $this->timeout = $timeout ?? (int) config('services.learning_analytics.timeout', 20);
- }
- /**
- * 获取学生知识点掌握情况统计
- *
- * @param string $studentId 学生ID
- * @return array
- */
- public function getStats(string $studentId): array
- {
- try {
- $response = Http::timeout($this->timeout)
- ->get($this->learningAnalyticsBase . '/api/knowledge-mastery/stats/' . $studentId);
- if ($response->successful()) {
- $body = $response->json();
- // 丰富知识点名称
- $body = $this->enrichWithKnowledgePointNames($body);
- // 添加知识图谱总数统计
- $graphStats = $this->getKnowledgeGraphStats();
- $body['graph_total_knowledge_points'] = $graphStats['total'] ?? 0;
- Log::info('KnowledgeMasteryService::getStats', ['student_id' => $studentId]);
- return [
- 'success' => true,
- 'data' => $body,
- ];
- }
- Log::warning('Knowledge mastery stats request failed', [
- 'student_id' => $studentId,
- 'status' => $response->status(),
- 'body' => $response->body(),
- ]);
- return [
- 'success' => false,
- 'error' => '获取知识点掌握情况失败: ' . $response->status(),
- ];
- } catch (\Throwable $e) {
- Log::error('Knowledge mastery stats exception', [
- 'student_id' => $studentId,
- 'error' => $e->getMessage(),
- ]);
- return [
- 'success' => false,
- 'error' => '获取知识点掌握情况异常: ' . $e->getMessage(),
- ];
- }
- }
- /**
- * 丰富知识点名称
- */
- private function enrichWithKnowledgePointNames(array $data): array
- {
- if (empty($data['details'])) {
- return $data;
- }
- // 收集所有kp_code
- $kpCodes = array_column($data['details'], 'kp_code');
- if (empty($kpCodes)) {
- return $data;
- }
- // 批量获取知识点名称
- $kpNames = $this->getKnowledgePointNames($kpCodes);
- // 丰富details数据
- foreach ($data['details'] as &$detail) {
- $kpCode = $detail['kp_code'] ?? null;
- if ($kpCode && isset($kpNames[$kpCode])) {
- $detail['kp_name'] = $kpNames[$kpCode];
- } else {
- $detail['kp_name'] = $kpCode; // fallback to code
- }
- }
- return $data;
- }
- /**
- * 批量获取知识点名称
- */
- private function getKnowledgePointNames(array $kpCodes): array
- {
- $result = [];
- foreach ($kpCodes as $kpCode) {
- $name = $this->getKnowledgePointName($kpCode);
- if ($name) {
- $result[$kpCode] = $name;
- }
- }
- return $result;
- }
- /**
- * 获取单个知识点名称(带缓存)
- */
- private function getKnowledgePointName(string $kpCode): ?string
- {
- $cacheKey = "kp_name_{$kpCode}";
- return Cache::remember($cacheKey, 3600, function () use ($kpCode) {
- try {
- $response = Http::timeout(5)
- ->get($this->knowledgeServiceBase . '/knowledge-points/' . $kpCode);
- if ($response->successful()) {
- $data = $response->json();
- return $data['cn_name'] ?? $data['en_name'] ?? null;
- }
- } catch (\Throwable $e) {
- Log::debug('Failed to get knowledge point name', [
- 'kp_code' => $kpCode,
- 'error' => $e->getMessage(),
- ]);
- }
- return null;
- });
- }
- /**
- * 获取知识图谱统计信息(带缓存)
- */
- public function getKnowledgeGraphStats(): array
- {
- return Cache::remember('knowledge_graph_stats', 3600, function () {
- try {
- $response = Http::timeout(10)
- ->get($this->knowledgeServiceBase . '/knowledge-points/');
- if ($response->successful()) {
- $data = $response->json();
- $items = $data['data'] ?? $data ?? [];
- return [
- 'total' => count($items),
- 'updated_at' => now()->toISOString(),
- ];
- }
- } catch (\Throwable $e) {
- Log::error('Failed to get knowledge graph stats', [
- 'error' => $e->getMessage(),
- ]);
- }
- return ['total' => 0];
- });
- }
- /**
- * 获取学生知识点图谱数据
- *
- * @param string $studentId 学生ID
- * @param string|null $examId 考试ID(可选,不指定则返回最新快照)
- * @return array
- */
- public function getGraph(string $studentId, ?string $examId = null): array
- {
- try {
- $query = array_filter(['exam_id' => $examId], fn($v) => filled($v));
- $response = Http::timeout($this->timeout)
- ->get($this->learningAnalyticsBase . '/api/knowledge-mastery/graph/' . $studentId, $query);
- if ($response->successful()) {
- $body = $response->json();
- Log::info('KnowledgeMasteryService::getGraph', ['student_id' => $studentId, 'exam_id' => $examId]);
- return [
- 'success' => true,
- 'data' => $body,
- ];
- }
- Log::warning('Knowledge graph request failed', [
- 'student_id' => $studentId,
- 'exam_id' => $examId,
- 'status' => $response->status(),
- 'body' => $response->body(),
- ]);
- return [
- 'success' => false,
- 'error' => '获取知识点图谱失败: ' . $response->status(),
- ];
- } catch (\Throwable $e) {
- Log::error('Knowledge graph exception', [
- 'student_id' => $studentId,
- 'exam_id' => $examId,
- 'error' => $e->getMessage(),
- ]);
- return [
- 'success' => false,
- 'error' => '获取知识点图谱异常: ' . $e->getMessage(),
- ];
- }
- }
- /**
- * 获取学生知识点图谱快照列表
- *
- * @param string $studentId 学生ID
- * @param int $limit 返回数量限制
- * @return array
- */
- public function getGraphSnapshots(string $studentId, int $limit = 10): array
- {
- try {
- $response = Http::timeout($this->timeout)
- ->get($this->learningAnalyticsBase . '/api/knowledge-mastery/graph/snapshots/' . $studentId, [
- 'limit' => $limit,
- ]);
- if ($response->successful()) {
- $body = $response->json();
- Log::info('KnowledgeMasteryService::getGraphSnapshots', ['student_id' => $studentId, 'limit' => $limit]);
- return [
- 'success' => true,
- 'data' => $body,
- ];
- }
- Log::warning('Knowledge graph snapshots request failed', [
- 'student_id' => $studentId,
- 'limit' => $limit,
- 'status' => $response->status(),
- 'body' => $response->body(),
- ]);
- return [
- 'success' => false,
- 'error' => '获取知识点图谱快照列表失败: ' . $response->status(),
- ];
- } catch (\Throwable $e) {
- Log::error('Knowledge graph snapshots exception', [
- 'student_id' => $studentId,
- 'limit' => $limit,
- 'error' => $e->getMessage(),
- ]);
- return [
- 'success' => false,
- 'error' => '获取知识点图谱快照列表异常: ' . $e->getMessage(),
- ];
- }
- }
- /**
- * 获取学生知识点掌握摘要(简化版)
- *
- * @param string $studentId 学生ID
- * @return array
- */
- public function getSummary(string $studentId): array
- {
- $stats = $this->getStats($studentId);
- if (!$stats['success']) {
- return $stats;
- }
- $data = $stats['data'];
- return [
- 'success' => true,
- 'data' => [
- 'student_id' => $data['student_id'] ?? $studentId,
- 'total' => $data['total_knowledge_points'] ?? 0,
- 'mastered' => $data['mastered_knowledge_points'] ?? 0,
- 'unmastered' => $data['unmastered_knowledge_points'] ?? 0,
- 'mastery_rate' => $data['mastery_rate'] ?? 0.0,
- 'mastery_percentage' => round(($data['mastery_rate'] ?? 0) * 100, 1) . '%',
- 'graph_total' => $data['graph_total_knowledge_points'] ?? 0,
- ],
- ];
- }
- /**
- * 创建知识点掌握度快照
- *
- * @param string $studentId 学生ID
- * @param string $snapshotType 快照类型 (exam/report/manual/scheduled)
- * @param string|null $sourceId 来源ID
- * @param string|null $sourceName 来源名称
- * @param string|null $notes 备注
- * @return array
- */
- public function createSnapshot(
- string $studentId,
- string $snapshotType = 'report',
- ?string $sourceId = null,
- ?string $sourceName = null,
- ?string $notes = null
- ): array {
- try {
- $response = Http::timeout($this->timeout)
- ->post($this->learningAnalyticsBase . '/api/knowledge-mastery/snapshot/' . $studentId, [
- 'snapshot_type' => $snapshotType,
- 'source_id' => $sourceId,
- 'source_name' => $sourceName,
- 'notes' => $notes,
- ]);
- if ($response->successful()) {
- $body = $response->json();
- Log::info('KnowledgeMasteryService::createSnapshot', [
- 'student_id' => $studentId,
- 'snapshot_type' => $snapshotType,
- 'snapshot_id' => $body['data']['snapshot_id'] ?? null,
- ]);
- return [
- 'success' => true,
- 'data' => $body['data'] ?? $body,
- ];
- }
- Log::warning('Create knowledge mastery snapshot failed', [
- 'student_id' => $studentId,
- 'status' => $response->status(),
- 'body' => $response->body(),
- ]);
- return [
- 'success' => false,
- 'error' => '创建知识点掌握度快照失败: ' . $response->status(),
- ];
- } catch (\Throwable $e) {
- Log::error('Create knowledge mastery snapshot exception', [
- 'student_id' => $studentId,
- 'error' => $e->getMessage(),
- ]);
- return [
- 'success' => false,
- 'error' => '创建知识点掌握度快照异常: ' . $e->getMessage(),
- ];
- }
- }
- }
|