|
@@ -100,18 +100,67 @@
|
|
|
<div
|
|
<div
|
|
|
class="mb-10 space-y-4"
|
|
class="mb-10 space-y-4"
|
|
|
x-data="studentMindmapPanel('{{ $this->getId() }}')"
|
|
x-data="studentMindmapPanel('{{ $this->getId() }}')"
|
|
|
- x-init="initMindmap()"
|
|
|
|
|
|
|
+ x-init="initEventListener(); initMindmap()"
|
|
|
data-knowledge-mindmap-root
|
|
data-knowledge-mindmap-root
|
|
|
>
|
|
>
|
|
|
<div class="relative overflow-hidden rounded-2xl border border-slate-200 shadow-sm bg-white">
|
|
<div class="relative overflow-hidden rounded-2xl border border-slate-200 shadow-sm bg-white">
|
|
|
<div
|
|
<div
|
|
|
wire:ignore
|
|
wire:ignore
|
|
|
id="student-mindmap"
|
|
id="student-mindmap"
|
|
|
- class="knowledge-mindmap-canvas relative h-[78vh] min-h-[680px] w-full"
|
|
|
|
|
|
|
+ class="knowledge-mindmap-canvas relative h-[64vh] min-h-[560px] w-full"
|
|
|
>
|
|
>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+ {{-- 内联知识点详情 --}}
|
|
|
|
|
+ <template x-if="selectedNode">
|
|
|
|
|
+ <div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
|
|
|
|
|
+ <div class="lg:col-span-2 rounded-xl border border-slate-200 bg-white p-4 shadow-sm">
|
|
|
|
|
+ <div class="flex items-start justify-between">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <p class="text-sm text-slate-500">选中知识点</p>
|
|
|
|
|
+ <h3 class="text-xl font-semibold text-slate-900" x-text="selectedNode.label || selectedNode.code"></h3>
|
|
|
|
|
+ <p class="text-sm text-slate-500 mt-1" x-text="`ID: ${selectedNode.id || ''} · Code: ${selectedNode.code || ''}`"></p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-right">
|
|
|
|
|
+ <p class="text-sm text-slate-500">掌握度</p>
|
|
|
|
|
+ <p class="text-2xl font-bold" x-text="(selectedNode.mastery * 100).toFixed(1) + '%'"></p>
|
|
|
|
|
+ <p class="text-xs text-slate-500" x-show="selectedNode.accuracy">准确率 <span x-text="(selectedNode.accuracy * 100).toFixed(1) + '%'"></span></p>
|
|
|
|
|
+ <p class="text-xs text-slate-500" x-show="selectedNode.attempts">练习次数 <span x-text="selectedNode.attempts"></span></p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="mt-4">
|
|
|
|
|
+ <p class="text-sm font-semibold text-slate-700 mb-2">技能要点</p>
|
|
|
|
|
+ <div class="flex flex-wrap gap-2">
|
|
|
|
|
+ <template x-if="selectedNode.skills && selectedNode.skills.length">
|
|
|
|
|
+ <template x-for="skill in selectedNode.skills" :key="skill">
|
|
|
|
|
+ <span class="rounded-full bg-slate-100 px-3 py-1 text-xs font-medium text-slate-700" x-text="skill"></span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <span x-show="!selectedNode.skills || !selectedNode.skills.length" class="text-sm text-slate-500">暂无技能要点</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="mt-4">
|
|
|
|
|
+ <a
|
|
|
|
|
+ class="inline-flex items-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-medium text-white hover:bg-indigo-700"
|
|
|
|
|
+ :href="selectedNode.code ? `/admin/knowledge-point-detail?kp_code=${encodeURIComponent(selectedNode.code)}` : '#'"
|
|
|
|
|
+ target="_blank"
|
|
|
|
|
+ >
|
|
|
|
|
+ 查看知识点详情
|
|
|
|
|
+ </a>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="rounded-xl border border-slate-200 bg-white p-4 shadow-sm space-y-2">
|
|
|
|
|
+ <p class="text-sm font-semibold text-slate-700">快速信息</p>
|
|
|
|
|
+ <div class="text-sm text-slate-600 space-y-1">
|
|
|
|
|
+ <p><span class="font-medium text-slate-900">ID:</span><span x-text="selectedNode.id"></span></p>
|
|
|
|
|
+ <p><span class="font-medium text-slate-900">Code:</span><span x-text="selectedNode.code"></span></p>
|
|
|
|
|
+ <p><span class="font-medium text-slate-900">推荐关注:</span><span x-text="selectedNode.recommended ? '是' : '否'"></span></p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
<x-mindmap.detail-drawer
|
|
<x-mindmap.detail-drawer
|
|
|
:open="$mindmapDrawerOpen"
|
|
:open="$mindmapDrawerOpen"
|
|
|
:details="$mindmapNodeDetails"
|
|
:details="$mindmapNodeDetails"
|
|
@@ -750,6 +799,28 @@
|
|
|
graphInstance: null,
|
|
graphInstance: null,
|
|
|
stats: { nodes: 0, extraEdges: 0 },
|
|
stats: { nodes: 0, extraEdges: 0 },
|
|
|
livewireId,
|
|
livewireId,
|
|
|
|
|
+ selectedNode: null,
|
|
|
|
|
+
|
|
|
|
|
+ initEventListener() {
|
|
|
|
|
+ window.addEventListener('mindmap-node-selected', (evt) => {
|
|
|
|
|
+ const model = evt.detail || {};
|
|
|
|
|
+ const code = model?.meta?.code || model?.id;
|
|
|
|
|
+ const mastery = model?.meta?.mastery_level ?? this.graphInstance?.masteryData?.[code]?.mastery_level ?? 0;
|
|
|
|
|
+ const accuracy = model?.meta?.accuracy_rate ?? this.graphInstance?.masteryData?.[code]?.accuracy_rate ?? null;
|
|
|
|
|
+ const attempts = model?.meta?.total_attempts ?? this.graphInstance?.masteryData?.[code]?.total_attempts ?? null;
|
|
|
|
|
+ this.selectedNode = {
|
|
|
|
|
+ id: model?.id,
|
|
|
|
|
+ code,
|
|
|
|
|
+ label: model?.label,
|
|
|
|
|
+ mastery,
|
|
|
|
|
+ accuracy,
|
|
|
|
|
+ attempts,
|
|
|
|
|
+ recommended: model?.meta?.recommended ?? false,
|
|
|
|
|
+ skills: model?.meta?.skills || this.graphInstance?.masteryData?.[code]?.skills || [],
|
|
|
|
|
+ };
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
async initMindmap() {
|
|
async initMindmap() {
|
|
|
if (!window.KnowledgeMindmapGraph) {
|
|
if (!window.KnowledgeMindmapGraph) {
|
|
|
return;
|
|
return;
|
|
@@ -760,6 +831,22 @@
|
|
|
livewireMethod: 'openMindmapDrawer',
|
|
livewireMethod: 'openMindmapDrawer',
|
|
|
highlightLowMastery: true,
|
|
highlightLowMastery: true,
|
|
|
livewireId: this.livewireId,
|
|
livewireId: this.livewireId,
|
|
|
|
|
+ onNodeSelect: (model) => {
|
|
|
|
|
+ const code = model?.meta?.code || model?.id;
|
|
|
|
|
+ const mastery = model?.meta?.mastery_level ?? this.graphInstance?.masteryData?.[code]?.mastery_level ?? 0;
|
|
|
|
|
+ const accuracy = model?.meta?.accuracy_rate ?? this.graphInstance?.masteryData?.[code]?.accuracy_rate ?? null;
|
|
|
|
|
+ const attempts = model?.meta?.total_attempts ?? this.graphInstance?.masteryData?.[code]?.total_attempts ?? null;
|
|
|
|
|
+ this.selectedNode = {
|
|
|
|
|
+ id: model?.id,
|
|
|
|
|
+ code,
|
|
|
|
|
+ label: model?.label,
|
|
|
|
|
+ mastery,
|
|
|
|
|
+ accuracy,
|
|
|
|
|
+ attempts,
|
|
|
|
|
+ recommended: model?.meta?.recommended ?? false,
|
|
|
|
|
+ skills: model?.meta?.skills || this.graphInstance?.masteryData?.[code]?.skills || [],
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
});
|
|
});
|
|
|
this.graphInstance.masteryData = @js($mindmapMasteryData ?? []);
|
|
this.graphInstance.masteryData = @js($mindmapMasteryData ?? []);
|
|
|
await this.graphInstance.init();
|
|
await this.graphInstance.init();
|