student-knowledge-graph.blade.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. <div>
  2. <div class="space-y-6">
  3. <!-- 标题和控制 -->
  4. <div class="bg-white shadow rounded-lg p-6">
  5. <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
  6. <div>
  7. <h2 class="text-2xl font-bold text-gray-900">学生知识图谱</h2>
  8. <p class="text-sm text-gray-600 mt-1">可视化展示学生的知识点掌握情况和依赖关系</p>
  9. </div>
  10. <div class="flex items-center gap-3">
  11. <select
  12. wire:model.live="selectedStudentId"
  13. class="rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
  14. >
  15. <option value="">-- 选择学生 --</option>
  16. @foreach ($students as $student)
  17. <option value="{{ $student['id'] }}">{{ $student['label'] }}</option>
  18. @endforeach
  19. </select>
  20. @if ($selectedStudent)
  21. <button
  22. wire:click="loadStudentData('{{ $selectedStudentId }}')"
  23. class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
  24. >
  25. <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  26. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
  27. </svg>
  28. 刷新
  29. </button>
  30. <button
  31. onclick="exportGraph()"
  32. class="inline-flex items-center px-3 py-2 border border-gray-300 text-sm leading-4 font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
  33. >
  34. <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  35. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
  36. </svg>
  37. 导出PNG
  38. </button>
  39. @endif
  40. </div>
  41. </div>
  42. @error('selectedStudentId')
  43. <p class="mt-2 text-sm text-red-600">{{ $message }}</p>
  44. @enderror
  45. </div>
  46. @if ($selectedStudent)
  47. <!-- 学生信息 -->
  48. <div class="bg-white shadow rounded-lg p-6">
  49. <div class="flex items-center gap-4">
  50. <div class="flex-shrink-0">
  51. <div class="w-16 h-16 rounded-full bg-indigo-100 flex items-center justify-center">
  52. <span class="text-2xl font-bold text-indigo-600">{{ substr($selectedStudent->name, 0, 1) }}</span>
  53. </div>
  54. </div>
  55. <div>
  56. <h3 class="text-lg font-semibold text-gray-900">{{ $selectedStudent->name }}</h3>
  57. <p class="text-sm text-gray-600">{{ $selectedStudent->grade }} {{ $selectedStudent->class_name }}</p>
  58. </div>
  59. </div>
  60. </div>
  61. @if ($isLoading)
  62. <!-- 加载状态 -->
  63. <div class="bg-white shadow rounded-lg p-12">
  64. <div class="flex flex-col items-center justify-center">
  65. <svg class="animate-spin h-12 w-12 text-indigo-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
  66. <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
  67. <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
  68. </svg>
  69. <p class="mt-4 text-sm text-gray-600">正在加载知识图谱数据...</p>
  70. </div>
  71. </div>
  72. @else
  73. <!-- 统计信息 -->
  74. @if (!empty($statistics))
  75. <div class="grid grid-cols-1 md:grid-cols-4 gap-6">
  76. <div class="bg-white shadow rounded-lg p-6">
  77. <div class="flex items-center">
  78. <div class="flex-shrink-0">
  79. <div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center">
  80. <svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  81. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
  82. </svg>
  83. </div>
  84. </div>
  85. <div class="ml-4">
  86. <p class="text-sm font-medium text-gray-500">平均掌握度</p>
  87. <p class="text-2xl font-semibold text-gray-900">{{ number_format($statistics['average_mastery'] * 100, 1) }}%</p>
  88. </div>
  89. </div>
  90. </div>
  91. <div class="bg-white shadow rounded-lg p-6">
  92. <div class="flex items-center">
  93. <div class="flex-shrink-0">
  94. <div class="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
  95. <svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  96. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  97. </svg>
  98. </div>
  99. </div>
  100. <div class="ml-4">
  101. <p class="text-sm font-medium text-gray-500">优秀 (≥80%)</p>
  102. <p class="text-2xl font-semibold text-gray-900">{{ $statistics['high_mastery_count'] }}</p>
  103. </div>
  104. </div>
  105. </div>
  106. <div class="bg-white shadow rounded-lg p-6">
  107. <div class="flex items-center">
  108. <div class="flex-shrink-0">
  109. <div class="w-8 h-8 bg-yellow-100 rounded-full flex items-center justify-center">
  110. <svg class="w-5 h-5 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  111. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
  112. </svg>
  113. </div>
  114. </div>
  115. <div class="ml-4">
  116. <p class="text-sm font-medium text-gray-500">中等 (40-80%)</p>
  117. <p class="text-2xl font-semibold text-gray-900">{{ $statistics['medium_mastery_count'] }}</p>
  118. </div>
  119. </div>
  120. </div>
  121. <div class="bg-white shadow rounded-lg p-6">
  122. <div class="flex items-center">
  123. <div class="flex-shrink-0">
  124. <div class="w-8 h-8 bg-red-100 rounded-full flex items-center justify-center">
  125. <svg class="w-5 h-5 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  126. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  127. </svg>
  128. </div>
  129. </div>
  130. <div class="ml-4">
  131. <p class="text-sm font-medium text-gray-500">待提高 (<40%)</p>
  132. <p class="text-2xl font-semibold text-gray-900">{{ $statistics['low_mastery_count'] }}</p>
  133. </div>
  134. </div>
  135. </div>
  136. </div>
  137. @endif
  138. <!-- 知识图谱 -->
  139. <div class="bg-white shadow rounded-lg p-6">
  140. <div class="flex items-center justify-between mb-4">
  141. <h3 class="text-lg font-semibold text-gray-900">知识点依赖关系图</h3>
  142. <div class="flex items-center gap-4 text-xs text-gray-500">
  143. <div class="flex items-center gap-1">
  144. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  145. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5M7.188 2.239l.777 2.897M5.136 7.965l-2.898-.777M13.95 4.05l-2.122 2.122m-5.657 5.656l-2.12 2.122"></path>
  146. </svg>
  147. <span>拖拽移动</span>
  148. </div>
  149. <div class="flex items-center gap-1">
  150. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  151. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
  152. </svg>
  153. <span>滚轮缩放</span>
  154. </div>
  155. <div class="flex items-center gap-1">
  156. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  157. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
  158. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
  159. </svg>
  160. <span>悬浮查看</span>
  161. </div>
  162. </div>
  163. </div>
  164. <div class="relative">
  165. <div id="knowledge-graph" class="w-full h-96 border border-gray-200 rounded-lg"></div>
  166. <!-- 图例 -->
  167. <div class="absolute top-4 right-4 bg-white p-4 rounded-lg shadow-lg border border-gray-200">
  168. <p class="text-xs font-semibold text-gray-700 mb-3">掌握度</p>
  169. <div class="space-y-2">
  170. <div class="flex items-center gap-2">
  171. <div class="w-4 h-4 rounded-full bg-green-500 border-2 border-white shadow-sm"></div>
  172. <span class="text-xs text-gray-700 font-medium">优秀 (≥80%)</span>
  173. </div>
  174. <div class="flex items-center gap-2">
  175. <div class="w-4 h-4 rounded-full bg-blue-500 border-2 border-white shadow-sm"></div>
  176. <span class="text-xs text-gray-700 font-medium">良好 (60-80%)</span>
  177. </div>
  178. <div class="flex items-center gap-2">
  179. <div class="w-4 h-4 rounded-full bg-yellow-500 border-2 border-white shadow-sm"></div>
  180. <span class="text-xs text-gray-700 font-medium">中等 (40-60%)</span>
  181. </div>
  182. <div class="flex items-center gap-2">
  183. <div class="w-4 h-4 rounded-full bg-orange-500 border-2 border-white shadow-sm"></div>
  184. <span class="text-xs text-gray-700 font-medium">待提高 (20-40%)</span>
  185. </div>
  186. <div class="flex items-center gap-2">
  187. <div class="w-4 h-4 rounded-full bg-red-500 border-2 border-white shadow-sm"></div>
  188. <span class="text-xs text-gray-700 font-medium">薄弱 (<20%)</span>
  189. </div>
  190. </div>
  191. <div class="mt-3 pt-3 border-t border-gray-200">
  192. <p class="text-xs text-gray-500">节点大小表示掌握程度</p>
  193. </div>
  194. </div>
  195. </div>
  196. </div>
  197. <!-- 掌握度分布图 -->
  198. @if (!empty($masteryData['masteries']))
  199. <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
  200. <div class="bg-white shadow rounded-lg p-6">
  201. <h3 class="text-lg font-semibold text-gray-900 mb-4">掌握度分布</h3>
  202. <canvas id="mastery-distribution" class="w-full h-64"></canvas>
  203. </div>
  204. <div class="bg-white shadow rounded-lg p-6">
  205. <h3 class="text-lg font-semibold text-gray-900 mb-4">知识点列表</h3>
  206. <div class="space-y-3 max-h-64 overflow-y-auto">
  207. @foreach ($masteryData['masteries'] as $mastery)
  208. <div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
  209. <div>
  210. <p class="text-sm font-medium text-gray-900">{{ $mastery['kp_code'] }}</p>
  211. <p class="text-xs text-gray-500">置信度: {{ number_format($mastery['confidence_level'] * 100, 1) }}%</p>
  212. </div>
  213. <div class="text-right">
  214. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
  215. style="background-color: {{ $this->getMasteryColor($mastery['mastery_level']) }}20; color: {{ $this->getMasteryColor($mastery['mastery_level']) }}">
  216. {{ number_format($mastery['mastery_level'] * 100, 1) }}%
  217. </span>
  218. </div>
  219. </div>
  220. @endforeach
  221. </div>
  222. </div>
  223. </div>
  224. @endif
  225. @endif
  226. @else
  227. <!-- 选择提示 -->
  228. <div class="bg-white shadow rounded-lg p-12">
  229. <div class="text-center">
  230. <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  231. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
  232. </svg>
  233. <h3 class="mt-4 text-lg font-medium text-gray-900">选择学生查看知识图谱</h3>
  234. <p class="mt-2 text-sm text-gray-500">从上方下拉列表中选择一个学生,系统将自动加载其知识图谱数据</p>
  235. </div>
  236. </div>
  237. @endif
  238. </div>
  239. <!-- 知识图谱脚本 -->
  240. @push('scripts')
  241. <script src="https://d3js.org/d3.v7.min.js"></script>
  242. <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  243. <script>
  244. document.addEventListener('livewire:initialized', () => {
  245. const knowledgeGraph = @this.knowledgePoints;
  246. if (knowledgeGraph && knowledgeGraph.nodes && knowledgeGraph.nodes.length > 0) {
  247. renderKnowledgeGraph(knowledgeGraph);
  248. renderMasteryChart(@this.masteryData.masteries);
  249. }
  250. // 监听数据更新
  251. Livewire.on('knowledgeGraphUpdated', (data) => {
  252. renderKnowledgeGraph(data);
  253. });
  254. });
  255. function renderKnowledgeGraph(data) {
  256. const container = document.getElementById('knowledge-graph');
  257. if (!container) return;
  258. // 清空容器
  259. container.innerHTML = '';
  260. const width = container.clientWidth;
  261. const height = container.clientHeight;
  262. const svg = d3.select('#knowledge-graph')
  263. .append('svg')
  264. .attr('width', width)
  265. .attr('height', height);
  266. // 创建力导向图
  267. const simulation = d3.forceSimulation(data.nodes)
  268. .force('link', d3.forceLink(data.links).id(d => d.id).distance(100))
  269. .force('charge', d3.forceManyBody().strength(-300))
  270. .force('center', d3.forceCenter(width / 2, height / 2));
  271. // 绘制边
  272. const link = svg.append('g')
  273. .selectAll('line')
  274. .data(data.links)
  275. .enter().append('line')
  276. .attr('stroke', '#999')
  277. .attr('stroke-opacity', 0.6)
  278. .attr('stroke-width', d => Math.sqrt(d.strength * 5));
  279. // 创建tooltip
  280. const tooltip = d3.select('body').append('div')
  281. .attr('class', 'knowledge-graph-tooltip')
  282. .style('position', 'absolute')
  283. .style('visibility', 'hidden')
  284. .style('background-color', 'rgba(0, 0, 0, 0.8)')
  285. .style('color', '#fff')
  286. .style('padding', '8px 12px')
  287. .style('border-radius', '6px')
  288. .style('font-size', '12px')
  289. .style('pointer-events', 'none')
  290. .style('z-index', '9999');
  291. // 绘制节点
  292. const node = svg.append('g')
  293. .selectAll('circle')
  294. .data(data.nodes)
  295. .enter().append('circle')
  296. .attr('r', d => d.size)
  297. .attr('fill', d => d.color)
  298. .attr('stroke', '#fff')
  299. .attr('stroke-width', 2)
  300. .style('cursor', 'pointer')
  301. .on('mouseover', function(event, d) {
  302. tooltip.style('visibility', 'visible')
  303. .html(`<strong>${d.label}</strong><br/>
  304. 掌握度: ${(d.mastery * 100).toFixed(1)}%<br/>
  305. 节点ID: ${d.id}`);
  306. })
  307. .on('mousemove', function(event) {
  308. tooltip.style('top', (event.pageY - 10) + 'px')
  309. .style('left', (event.pageX + 10) + 'px');
  310. })
  311. .on('mouseout', function() {
  312. tooltip.style('visibility', 'hidden');
  313. })
  314. .on('click', function(event, d) {
  315. showNodeDetails(d);
  316. })
  317. .call(d3.drag()
  318. .on('start', dragstarted)
  319. .on('drag', dragged)
  320. .on('end', dragended));
  321. // 添加标签
  322. const label = svg.append('g')
  323. .selectAll('text')
  324. .data(data.nodes)
  325. .enter().append('text')
  326. .text(d => d.label)
  327. .attr('font-size', '12px')
  328. .attr('fill', '#333')
  329. .attr('text-anchor', 'middle')
  330. .attr('dy', '.35em');
  331. // 更新位置
  332. simulation.on('tick', () => {
  333. link
  334. .attr('x1', d => d.source.x)
  335. .attr('y1', d => d.source.y)
  336. .attr('x2', d => d.target.x)
  337. .attr('y2', d => d.target.y);
  338. node
  339. .attr('cx', d => d.x)
  340. .attr('cy', d => d.y);
  341. label
  342. .attr('x', d => d.x)
  343. .attr('y', d => d.y + d.size + 15);
  344. });
  345. function dragstarted(event, d) {
  346. if (!event.active) simulation.alphaTarget(0.3).restart();
  347. d.fx = d.x;
  348. d.fy = d.y;
  349. }
  350. function dragged(event, d) {
  351. d.fx = event.x;
  352. d.fy = event.y;
  353. }
  354. function dragended(event, d) {
  355. if (!event.active) simulation.alphaTarget(0);
  356. d.fx = null;
  357. d.fy = null;
  358. }
  359. // 添加缩放功能
  360. const zoom = d3.zoom()
  361. .scaleExtent([0.5, 3])
  362. .on('zoom', (event) => {
  363. svg.selectAll('g').attr('transform', event.transform);
  364. });
  365. svg.call(zoom);
  366. // 节点详情展示函数
  367. function showNodeDetails(nodeData) {
  368. alert(`知识点详情:\n\n名称: ${nodeData.label}\n代码: ${nodeData.id}\n掌握度: ${(nodeData.mastery * 100).toFixed(1)}%\n\n点击确定继续浏览图谱`);
  369. }
  370. // 导出PNG功能
  371. window.exportGraph = function() {
  372. const container = document.getElementById('knowledge-graph');
  373. if (!container) return;
  374. const svgElement = container.querySelector('svg');
  375. if (!svgElement) return;
  376. // 创建canvas
  377. const canvas = document.createElement('canvas');
  378. const ctx = canvas.getContext('2d');
  379. const data = (new XMLSerializer()).serializeToString(svgElement);
  380. const DOMURL = window.URL || window.webkitURL || window;
  381. const img = new Image();
  382. const svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
  383. const url = DOMURL.createObjectURL(svgBlob);
  384. img.onload = function () {
  385. canvas.width = svgElement.clientWidth;
  386. canvas.height = svgElement.clientHeight;
  387. ctx.fillStyle = '#ffffff';
  388. ctx.fillRect(0, 0, canvas.width, canvas.height);
  389. ctx.drawImage(img, 0, 0);
  390. DOMURL.revokeObjectURL(url);
  391. // 下载图片
  392. const link = document.createElement('a');
  393. link.download = `知识图谱_${new Date().getTime()}.png`;
  394. link.href = canvas.toDataURL('image/png');
  395. link.click();
  396. };
  397. img.src = url;
  398. };
  399. }
  400. function renderMasteryChart(masteries) {
  401. const ctx = document.getElementById('mastery-distribution');
  402. if (!ctx) return;
  403. // 分类数据
  404. const ranges = {
  405. '优秀 (≥80%)': 0,
  406. '良好 (60-80%)': 0,
  407. '中等 (40-60%)': 0,
  408. '待提高 (20-40%)': 0,
  409. '薄弱 (<20%)': 0
  410. };
  411. masteries.forEach(m => {
  412. const mastery = m.mastery_level * 100;
  413. if (mastery >= 80) ranges['优秀 (≥80%)']++;
  414. else if (mastery >= 60) ranges['良好 (60-80%)']++;
  415. else if (mastery >= 40) ranges['中等 (40-60%)']++;
  416. else if (mastery >= 20) ranges['待提高 (20-40%)']++;
  417. else ranges['薄弱 (<20%)']++;
  418. });
  419. new Chart(ctx, {
  420. type: 'bar',
  421. data: {
  422. labels: Object.keys(ranges),
  423. datasets: [{
  424. label: '知识点数量',
  425. data: Object.values(ranges),
  426. backgroundColor: [
  427. '#10b981',
  428. '#3b82f6',
  429. '#f59e0b',
  430. '#f97316',
  431. '#ef4444'
  432. ]
  433. }]
  434. },
  435. options: {
  436. responsive: true,
  437. maintainAspectRatio: false,
  438. plugins: {
  439. legend: {
  440. display: false
  441. }
  442. },
  443. scales: {
  444. y: {
  445. beginAtZero: true,
  446. ticks: {
  447. stepSize: 1
  448. }
  449. }
  450. }
  451. }
  452. });
  453. }
  454. </script>
  455. @endpush
  456. </div>