Version 0.1.1 rise to flask app factory
This commit is contained in:
53
Html/apps/static/binary_search.html
Normal file
53
Html/apps/static/binary_search.html
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>二分查找与二分答案</h1>
|
||||
<h2>二分查找</h2>
|
||||
<h3>引入</h3>
|
||||
<p>二分是一个很简单基础,但很重要的知识点,为以后许多高级的数据结构与算法铺垫。</p>
|
||||
<p>下面是一个用二分的简单场景:</p>
|
||||
<p>假设小明从0到1000之间选择了一个数字但不告诉你,你可以不断猜测这个数,每次猜测小明会告知你的猜测得过大还是过小,问最多几次就一定能猜中?</p>
|
||||
<p>答案是利用二分查找的原理,猜测11次即可。</p>
|
||||
<ol>
|
||||
<li>对于0到1000的答案备选区,猜测中位数500,假设过小,</li>
|
||||
<li>则对于501到1000的答案备选区,猜测750,假设过大</li>
|
||||
<li>则对于501到749的答案备选区,猜测625,假设过小,</li>
|
||||
<li>则对于626到749区间......</li>
|
||||
<li>(688-749)</li>
|
||||
<li>(718-749)</li>
|
||||
<li>(734-749)</li>
|
||||
<li>(742-749)</li>
|
||||
<li>(746-749)</li>
|
||||
<li>(748-749)</li>
|
||||
<li>(749-749)</li>
|
||||
</ol>
|
||||
<p>在最差的情况下,第11次的答案备选区就一定长度为1了,也就是必然是答案。</p>
|
||||
<p>因此如果序列是有序的,就可以通过二分查找快速定位所需要的数据。</p>
|
||||
<h4>思考题(询问Agent以学习计算方法,或验证你的答案)</h4>
|
||||
<p>对于上面那个题目,如果问题区间是1到4000,最差情况下需要猜测几次?</p>
|
||||
<h3>练习:二分查找</h3>
|
||||
<p>试试对于下面的题目,用代码实现一下二分查找。</p>
|
||||
<h4>题目:有序数组寻址</h4>
|
||||
<p>给出一个长度为n的有序数组(从小到大),有q次询问,对于每次询问,输出指定数在数组中的下标。如果不存在则输出-1。</p>
|
||||
<h5>输入</h5>
|
||||
<p>第一行一个整数n。(1<=n<=10^5)</p>
|
||||
<p>第二行n个用空格分开的整数ai。(0<=ai<=10^8)</p>
|
||||
<p>第三行一个整数q,表示询问的次数。(1<=q<=10^4)</p>
|
||||
<p>后q行,每行一个整数b,表示询问的数。(0<=b<=10^8)</p>
|
||||
<h5>输出</h5>
|
||||
<p>q行,每行一个整数,对应每次询问的返回结果。</p>
|
||||
<h5>提示:</h5>
|
||||
<p>完成代码后,通知Agent进行评测。</p>
|
||||
<p>如果你还不完全会这个算法,询问Agent获取提示并进行学习。</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
158
Html/apps/static/css/course.css
Normal file
158
Html/apps/static/css/course.css
Normal file
@@ -0,0 +1,158 @@
|
||||
/* Reset some default styles */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Body & Page Background */
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* 页眉导航栏 */
|
||||
.navbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #2575fc;
|
||||
padding: 10px 30px;
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.navbar .logo h1 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.navbar-links a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin: 0 15px;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.navbar-links a:hover {
|
||||
color: #f1c40f;
|
||||
}
|
||||
|
||||
.navbar .avatar img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
/* 课程详情页面主体部分 */
|
||||
.course-details {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
|
||||
/* 上半部分:课程封面和课程详情 */
|
||||
.course-overview {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 30px;
|
||||
max-height: 200px;
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
.course-cover {
|
||||
width: 40%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cover-image {
|
||||
|
||||
height: 100%;
|
||||
width: auto;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.course-info {
|
||||
width: 55%;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.course-title {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.course-author {
|
||||
font-size: 16px;
|
||||
color: #777;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.course-description {
|
||||
font-size: 16px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/* 下半部分:课程教案列表 */
|
||||
.lesson-plans {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.lesson-plans h3 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 课程教案卡片容器 */
|
||||
.lesson-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
/* 课程教案卡片 */
|
||||
.lesson-card {
|
||||
width: 200px;
|
||||
height: 300px;
|
||||
background-color: white;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.lesson-card:hover {
|
||||
transform: translateY(-10px); /* 提升效果 */
|
||||
}
|
||||
|
||||
.lesson-image {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.lesson-info {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.lesson-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.lesson-description {
|
||||
font-size: 14px;
|
||||
color: #777;
|
||||
}
|
||||
196
Html/apps/static/css/dashboard.css
Normal file
196
Html/apps/static/css/dashboard.css
Normal file
@@ -0,0 +1,196 @@
|
||||
/* Reset some default styles */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Body & Page Background */
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 页眉导航栏 */
|
||||
.navbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.navbar .logo h1 {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.navbar-links a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin: 0 15px;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s;
|
||||
}
|
||||
|
||||
.navbar-links a:hover {
|
||||
color: #f1c40f;
|
||||
}
|
||||
|
||||
.navbar .avatar img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
/* Dashboard 主体部分 */
|
||||
.dashboard {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.dashboard-title {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
/* 课程卡片容器 */
|
||||
.course-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 课程卡片 */
|
||||
.course-card {
|
||||
width: 300px;
|
||||
height: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: white;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-top: auto; /* 将按钮推到父元素的底部 */
|
||||
}
|
||||
|
||||
.course-card:hover {
|
||||
transform: translateY(-10px); /* 提升效果 */
|
||||
}
|
||||
|
||||
.course-image {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.course-info {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.course-name {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.course-description {
|
||||
font-size: 14px;
|
||||
color: #777;
|
||||
margin-top: 10px;
|
||||
}
|
||||
/* 右侧滑出进度卡片样式 */
|
||||
.course-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: -400px; /* 初始时在屏幕外 */
|
||||
width: 400px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
|
||||
padding: 30px;
|
||||
transition: right 0.3s ease;
|
||||
z-index: 9999;
|
||||
border-radius: 15px; /* 添加圆角 */
|
||||
}
|
||||
|
||||
.course-progress.open {
|
||||
right: 0; /* 打开时显示 */
|
||||
}
|
||||
|
||||
.progress-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
/* 章节和子章节样式 */
|
||||
.chapter-list {
|
||||
list-style-type: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.chapter-item {
|
||||
margin: 5px 0;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.chapter-item .chapter-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.chapter-item .sub-chapter-list {
|
||||
display: none; /* 初始状态下子章节隐藏 */
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.chapter-item.open .sub-chapter-list {
|
||||
display: block; /* 展开时显示子章节 */
|
||||
}
|
||||
|
||||
.chapter-item:hover {
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* 子章节的样式 */
|
||||
.sub-chapter-item {
|
||||
margin: 3px 0;
|
||||
padding: 3px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.sub-chapter-item:hover {
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
298
Html/apps/static/css/desktop.css
Normal file
298
Html/apps/static/css/desktop.css
Normal file
@@ -0,0 +1,298 @@
|
||||
|
||||
/* 左右两侧的页面内容 */
|
||||
.sidebar {
|
||||
background-color: #f0f0f0;
|
||||
padding: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
.chatbox {
|
||||
flex-grow: 1;
|
||||
padding: 20px;
|
||||
height: 75%;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
max-width: 70%;
|
||||
padding: 10px 15px;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.user-message {
|
||||
background-color: #d1e7dd;
|
||||
text-align: right;
|
||||
margin-left: auto;
|
||||
}
|
||||
.server-message {
|
||||
background-color: #f1f1f1;
|
||||
text-align: left;
|
||||
margin-right: auto;
|
||||
}
|
||||
textarea {
|
||||
flex-grow: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
resize: none;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
margin-left: 10px;
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
pre {
|
||||
background-color: #eee;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
code {
|
||||
font-family: monospace;
|
||||
}
|
||||
/* 让父容器为flex布局 */
|
||||
.maxcontainer {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
/* 中间的拖拽条 */
|
||||
.resizer {
|
||||
width: 5px;
|
||||
background-color: #ccc;
|
||||
cursor: ew-resize;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chatbox-header {
|
||||
padding: 10px;
|
||||
background-color: #f1f1f1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
|
||||
.input-area {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
padding: 10px;
|
||||
background-color: #f1f1f1;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.slider-container, .language-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.slider-container input[type="range"] {
|
||||
width: 70%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.btn-group-toggle .btn {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#leftSidebar, .vscode-web, #rightSidebar {
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#dragbar, #dragbar2 {
|
||||
background-color: #ccc;
|
||||
cursor: col-resize;
|
||||
}
|
||||
/* 主容器,使用 grid 布局 */
|
||||
#maxcontainer {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 5px 3fr 5px 1fr; /* 默认宽度比例 */
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
/* 各区域基础样式 */
|
||||
.sidebar {
|
||||
overflow: auto; /* 确保内容可以滚动 */
|
||||
}
|
||||
|
||||
.vscode-web {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.resizer {
|
||||
background-color: #ccc;
|
||||
cursor: col-resize;
|
||||
width: 5px; /* 设置拖动条宽度 */
|
||||
}
|
||||
|
||||
.gutter {
|
||||
background-color: #ccc; /* 分隔条颜色 */
|
||||
cursor: col-resize;
|
||||
}#container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 5px 3fr 5px 1fr; /* 初始比例 */
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#leftSidebar, #vscodeWeb, #rightSidebar {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#dragbar, #dragbar2 {
|
||||
background-color: #ccc;
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* 设置每个子框的基本样式 */
|
||||
.progress-box {
|
||||
height: 100%; /* 高度为 100%,撑满容器 */
|
||||
display: flex;
|
||||
flex-direction: row; /* 使子框横向排列 */
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.progress-title {
|
||||
height: 60px; /* 每个进度节点的高度 */
|
||||
text-align: center;
|
||||
line-height: 60px; /* 垂直居中 */
|
||||
margin: 2px; /* 水平方向上的间隔 */
|
||||
border: 1px solid #ddd;
|
||||
transition: background-color 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.green {
|
||||
background-color: green;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.white {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.progress-box > .progress-title:last-child {
|
||||
margin-bottom: 0; /* 防止最后一个子框出现多余的间距 */
|
||||
}
|
||||
|
||||
/* 进度条详细信息的样式 */
|
||||
#progress-detail {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: none;
|
||||
padding: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.close-button {
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
padding-bottom: 2px;
|
||||
padding-top: 2px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
/* 新增的侧边工具栏样式 */
|
||||
.sidebar-tools {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: -250px; /* 初始隐藏 */
|
||||
width: 250px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 10px 0 0 10px;
|
||||
transition: right 0.3s ease-in-out;
|
||||
z-index: 1000;
|
||||
}
|
||||
.sidebar-tools.open {
|
||||
right: 0;
|
||||
}
|
||||
.sidebar-tools .tool-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
.sidebar-tools .tool-button:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.sidebar-tools .tool-button .icon {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 10px;
|
||||
background-color: #007bff;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
.sidebar-tools .tool-button .description {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.toggle-button {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: -10px; /* 初始隐藏 */
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-color: #007bff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
transition: right 0.3s ease-in-out;
|
||||
z-index: 1001;
|
||||
}
|
||||
.toggle-button.open {
|
||||
right: 250px;
|
||||
}
|
||||
.toggle-button .icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
153
Html/apps/static/css/index.css
Normal file
153
Html/apps/static/css/index.css
Normal file
@@ -0,0 +1,153 @@
|
||||
|
||||
/* General reset */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
/* Body & Page Background */
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
footer {
|
||||
background-color: #f8f9fa;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
/* Header styles */
|
||||
header {
|
||||
background-color: #2575fc;
|
||||
padding: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.site-name h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.nav ul {
|
||||
list-style-type: none;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.nav ul li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.nav ul li a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.user-avatar img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Main content styles */
|
||||
main {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.course-selection h2 {
|
||||
font-size: 28px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.course-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.course-card {
|
||||
background-color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 8px;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-top: auto; /* 将按钮推到父元素的底部 */
|
||||
}
|
||||
.course-card:hover {
|
||||
transform: translateY(-10px); /* 提升效果 */
|
||||
}
|
||||
.course-card img {
|
||||
width: 100%;
|
||||
height: 261px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.course-card h3 {
|
||||
padding: 15px;
|
||||
font-size: 20px;
|
||||
color: #2575fc;
|
||||
}
|
||||
|
||||
.course-card p {
|
||||
padding: 0 15px;
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
|
||||
.select-button:hover {
|
||||
background-color: #113c86;
|
||||
}
|
||||
|
||||
.selected-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #8a8b8c;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
cursor: not-allowed;
|
||||
margin-top: auto; /* 将按钮推到父元素的底部 */
|
||||
}
|
||||
|
||||
/* Footer styles */
|
||||
footer {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
188
Html/apps/static/css/login.css
Normal file
188
Html/apps/static/css/login.css
Normal file
@@ -0,0 +1,188 @@
|
||||
/* Reset some default styles */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Body & Page background */
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background: linear-gradient(135deg, #70ff88, #e6d05f); /* 美丽的渐变背景 */
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background-color: white;
|
||||
padding: 40px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.login-switch {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.switch-btn {
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.switch-btn:hover {
|
||||
background-color: #6a11cb;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 16px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.input-group input:focus {
|
||||
border-color: #2575fc;
|
||||
outline: none;
|
||||
}
|
||||
/* 基本按钮样式 */
|
||||
.role-btn {
|
||||
background-color: #2575fc; /* 默认的蓝色背景(学生登录) */
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 10px 20px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s, transform 0.3s; /* 背景色平滑过渡,按钮缩放 */
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 按钮悬停效果 */
|
||||
.role-btn:hover {
|
||||
background-color: #6a11cb; /* 悬停时变为深蓝色 */
|
||||
transform: scale(1.05); /* 按钮放大效果 */
|
||||
}
|
||||
|
||||
/* 切换到教师登录时的背景色 */
|
||||
.teacher-login .role-btn {
|
||||
background-color: #005848; /* 深蓝色背景(教师登录) */
|
||||
}
|
||||
|
||||
/* 切换到教师登录时的悬停效果 */
|
||||
.teacher-login .role-btn:hover {
|
||||
background-color: #017c6e;
|
||||
}
|
||||
.login-btn {
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
padding: 14px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
width: 100%;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
|
||||
}
|
||||
|
||||
.login-btn:hover {
|
||||
background-color: #6a11cb;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.forgot-password a {
|
||||
color: #2575fc;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.forgot-password a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.social-login {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.social-btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
margin: 5px 0;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.social-btn.google {
|
||||
background-color: #db4437;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.social-btn.google:hover {
|
||||
background-color: #c1351d;
|
||||
}
|
||||
|
||||
.social-btn.facebook {
|
||||
background-color: #3b5998;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.social-btn.facebook:hover {
|
||||
background-color: #2d4373;
|
||||
}
|
||||
199
Html/apps/static/css/teacherboard.css
Normal file
199
Html/apps/static/css/teacherboard.css
Normal file
@@ -0,0 +1,199 @@
|
||||
/* Teacherboard 样式 */
|
||||
.teacherboard {
|
||||
padding: 20px;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.teacherboard-title {
|
||||
text-align: center;
|
||||
font-size: 32px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.course-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.course-card {
|
||||
width: 250px;
|
||||
background-color: #f9f9f9;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.course-image {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.course-info {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.course-name {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.course-description {
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/* 课程目录弹出框 */
|
||||
|
||||
.course-details {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: -400px;
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 20px;
|
||||
transition: right 0.3s ease;
|
||||
z-index: 9999;
|
||||
border-radius: 15px; /* 添加圆角 */
|
||||
}
|
||||
|
||||
.course-details.open {
|
||||
right: 0; /* 打开时显示 */
|
||||
}
|
||||
|
||||
.details-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.details-header button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.details-content {
|
||||
padding-right: 20px;
|
||||
}
|
||||
.lesson-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between; /* 让垃圾桶靠右 */
|
||||
padding: 5px 0;
|
||||
}
|
||||
.lesson-text {
|
||||
cursor: pointer; /* 鼠标悬停时变成手指 */
|
||||
transition: color 0.3s;
|
||||
flex: 1; /* 占据左侧空间 */
|
||||
}
|
||||
|
||||
.lesson-text:hover {
|
||||
color: #2575fc; /* 这里你可以设置悬停时的颜色 */
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.icon-btn:hover {
|
||||
color: #2575fc; /* hover 高亮 */
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
color: #c0392b; /* 红色垃圾桶 */
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
color: #e74c3c;
|
||||
}
|
||||
.new-chapter-input {
|
||||
width: 200px;
|
||||
padding: 8px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-left: 8px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.icon-btn:hover {
|
||||
color: #2575fc; /* hover 高亮 */
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
color: #c0392b; /* 红色垃圾桶 */
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
|
||||
.add-chapter-btn {
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 编辑弹窗 */
|
||||
.edit-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 400px;
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.edit-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.edit-modal-content input,
|
||||
.edit-modal-content textarea {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.edit-modal-content button {
|
||||
background-color: #2575fc;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
20
Html/apps/static/example.html
Normal file
20
Html/apps/static/example.html
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>这是一个Makedown文件</h2>
|
||||
<h3>教学目标</h3>
|
||||
<h3>第一章:什么是计算机</h3>
|
||||
<h4>例1-1:计算机的组成部分是</h4>
|
||||
<h3>第二章:什么是算法</h3>
|
||||
<p><img alt="图片" src="./image/example/p1.png" /></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
Html/apps/static/image/CS101/CS101.png
Normal file
BIN
Html/apps/static/image/CS101/CS101.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
Html/apps/static/image/algorithm/book_cover.png
Normal file
BIN
Html/apps/static/image/algorithm/book_cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 912 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
BIN
Html/apps/static/image/example/p1.png
Normal file
BIN
Html/apps/static/image/example/p1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
258
Html/apps/static/js/chatbox.js
Normal file
258
Html/apps/static/js/chatbox.js
Normal file
@@ -0,0 +1,258 @@
|
||||
|
||||
var socket;
|
||||
let system_message_idx=0
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
data = window.appData;
|
||||
console.log(data);
|
||||
socket = io('ws://localhost:5551/agent',{
|
||||
query:{
|
||||
username:data.username,
|
||||
folder:data.folder
|
||||
}
|
||||
});
|
||||
socket.on('connect', function() {
|
||||
console.log('Connected to server');
|
||||
socket.emit('login',JSON.stringify(data));
|
||||
});
|
||||
// 监听来自服务器的消息
|
||||
socket.on('message', function(data) {
|
||||
// 显示服务器的回复消息
|
||||
const serverMessage = document.createElement('div');
|
||||
serverMessage.innerHTML = `<div class="chat-message server-message"><b>华实君:</b> ${marked.parse(data)}</div>`;
|
||||
document.getElementById('chatbox').appendChild(serverMessage);
|
||||
|
||||
// 滚动到最新消息
|
||||
document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight;
|
||||
});
|
||||
socket.on('request_function', function(data){
|
||||
try {
|
||||
console.log("request_function", data);
|
||||
if (typeof data === 'string') {
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const element = data[i]
|
||||
const requestMessage = document.createElement('div');
|
||||
requestMessage.className = 'chat-message server-message';
|
||||
const approveButton = document.createElement('button');
|
||||
approveButton.innerText = '批准';
|
||||
approveButton.data = element;
|
||||
approveButton.style.width = '100%';
|
||||
approveButton.style.borderRadius = '4px';
|
||||
approveButton.onclick = function(event) {
|
||||
console.log(element)
|
||||
socket.emit('message', JSON.stringify({type:'function', data:element}));
|
||||
event.currentTarget.disabled = true;
|
||||
event.currentTarget.style.backgroundColor = 'gray';
|
||||
event.currentTarget.style.color = 'white'; // 可选:设置文字颜色为白色,以便更清晰地显示
|
||||
event.currentTarget.style.border = 'none'; // 可选:去掉边框
|
||||
};
|
||||
// 将按钮添加到消息气泡中
|
||||
requestMessage.innerHTML = `<b>Function:</b> ${element.name}(${JSON.stringify(element.arguments)})<br>`;
|
||||
requestMessage.appendChild(approveButton);
|
||||
document.getElementById('chatbox').appendChild(requestMessage);
|
||||
document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
});
|
||||
socket.on('next_chapter', function(data){
|
||||
next_chapter(data);
|
||||
});
|
||||
socket.on('chapter_score',function(data){
|
||||
if (typeof data === 'string'){
|
||||
data = JSON.parse(data);
|
||||
}
|
||||
console.log(data)
|
||||
const scoreMessage = document.createElement('div');
|
||||
scoreMessage.className = 'chat-message server-message';
|
||||
scoreMessage.innerHTML = `<b>Chapter ${data.chapter_id} Score:</b> ${JSON.stringify(data.data.content.speak)}`;
|
||||
document.getElementById('chatbox').appendChild(scoreMessage);
|
||||
document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight;
|
||||
})
|
||||
socket.on('system_message',function(data){
|
||||
console.log(data)
|
||||
let systemMessage = document.createElement('div');
|
||||
systemMessage.className = 'chat-message server-message';
|
||||
let closeButton = document.createElement('button');
|
||||
closeButton.className = 'close-button'; // 可以根据需要添加样式类
|
||||
closeButton.innerHTML = '×'; // 关闭按钮的文本内容
|
||||
closeButton.style.marginRight = '10px'; // 可选:设置关闭按钮的右边距
|
||||
|
||||
systemMessage.appendChild(closeButton);
|
||||
systemMessage.innerHTML += `<b>系统提示: </b> ${data}`;
|
||||
systemMessage.id = 'system_message_'+system_message_idx;
|
||||
system_message_idx+=1
|
||||
document.getElementById('chatbox').appendChild(systemMessage);
|
||||
document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight;
|
||||
$('.close-button').on('click', function(event) {
|
||||
$(this).css({
|
||||
'background-color': 'gray',
|
||||
'color': 'white', // 可选:设置文字颜色为白色,以便更清晰地显示
|
||||
'border': 'none' // 可选:去掉边框
|
||||
});
|
||||
$(this).parent().remove();
|
||||
});
|
||||
setTimeout(function() {
|
||||
$(systemMessage.id).remove();
|
||||
}, 5000); // 5000 毫秒 = 5 秒
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// 控制文字大小的滑块
|
||||
const fontSizeSlider = document.getElementById('fontSizeSlider');
|
||||
const chatbox = document.getElementById('chatbox');
|
||||
|
||||
fontSizeSlider.addEventListener('input', function() {
|
||||
console.log(fontSizeSlider.value);
|
||||
chatbox.style.fontSize = fontSizeSlider.value + 'px';
|
||||
});
|
||||
|
||||
// 语言切换按钮
|
||||
const englishRadio = document.getElementById('english');
|
||||
const chineseRadio = document.getElementById('chinese');
|
||||
|
||||
const englishLabel = document.getElementById('label_for_en');
|
||||
const chineseLabel = document.getElementById('label_for_zh');
|
||||
let language = 'zh'; // 默认语言
|
||||
|
||||
// 切换语言事件
|
||||
englishRadio.addEventListener('change', function() {
|
||||
if (englishRadio.checked) {
|
||||
language = 'en';
|
||||
englishLabel.classList.add('active');
|
||||
chineseLabel.classList.remove('active');
|
||||
}
|
||||
socket.emit('language',language);
|
||||
});
|
||||
|
||||
chineseRadio.addEventListener('change', function() {
|
||||
if (chineseRadio.checked) {
|
||||
language = 'zh';
|
||||
chineseLabel.classList.add('active');
|
||||
englishLabel.classList.remove('active');
|
||||
}
|
||||
socket.emit('language',language);
|
||||
});
|
||||
|
||||
|
||||
function sendInitiativeFunctionCall(function_name){
|
||||
socket.emit('initiative', {'name': function_name});
|
||||
}
|
||||
// 发送消息
|
||||
function sendMessage() {
|
||||
const input = document.getElementById('messageInput').value;
|
||||
if (input.trim() === '') return;
|
||||
|
||||
// 使用 marked.js 解析 markdown
|
||||
const markdownHtml = marked.parse(input);
|
||||
|
||||
// 显示用户发送的消息
|
||||
const userMessage = document.createElement('div');
|
||||
userMessage.innerHTML = `<div class="chat-message user-message"><b>你:</b> ${markdownHtml}</div>`;
|
||||
document.getElementById('chatbox').appendChild(userMessage);
|
||||
|
||||
// 发送消息到服务器
|
||||
socket.emit('message', JSON.stringify({data: input, type:'text'}));
|
||||
|
||||
// 清空输入框
|
||||
document.getElementById('messageInput').value = '';
|
||||
|
||||
// 滚动到最新消息
|
||||
document.getElementById('chatbox').scrollTop = document.getElementById('chatbox').scrollHeight;
|
||||
}
|
||||
|
||||
let currentChapterIndex = -1;
|
||||
function next_chapter(data) {
|
||||
// 获取所有的 h3 元素
|
||||
var iframe = document.getElementById('markdown-content-iframe');
|
||||
|
||||
// 访问 iframe 的文档对象
|
||||
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
|
||||
var titles = []
|
||||
var h3Elements = iframeDocument.querySelectorAll('h3');
|
||||
console.log("h3Elements next")
|
||||
if (currentChapterIndex >= h3Elements.length) {
|
||||
return; // 如果已经到了最后一个章节,则不进行任何操作
|
||||
}
|
||||
|
||||
// 隐藏当前章节及其后的内容
|
||||
for (let i = 0; i < h3Elements.length; i++) {
|
||||
h3Elements[i].style.display = 'none';
|
||||
titles.push(h3Elements[i].innerText)
|
||||
let nextSibling = h3Elements[i].nextElementSibling;
|
||||
while (nextSibling && nextSibling.tagName !== 'H3') {
|
||||
nextSibling.style.display = 'none';
|
||||
nextSibling = nextSibling.nextElementSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// 显示下一个章节及其后的内容,直到再下一个h3元素或结束
|
||||
if (currentChapterIndex + 1 < h3Elements.length) {
|
||||
h3Elements[currentChapterIndex + 1].style.display = 'block';
|
||||
let nextSibling = h3Elements[currentChapterIndex + 1].nextElementSibling;
|
||||
while (nextSibling && nextSibling.tagName !== 'H3') {
|
||||
nextSibling.style.display = 'block';
|
||||
nextSibling = nextSibling.nextElementSibling;
|
||||
}
|
||||
}
|
||||
currentChapterIndex++;
|
||||
|
||||
generateProgressBar(h3Elements.length, currentChapterIndex, titles);
|
||||
}
|
||||
|
||||
function generateProgressBar(N, idx, titles) {
|
||||
const container = document.getElementById('markdown-content-process');
|
||||
container.innerHTML = ''; // 清空内容
|
||||
|
||||
// 创建进度条的外框
|
||||
const progressBox = document.createElement('div');
|
||||
progressBox.className = 'progress-box';
|
||||
|
||||
// 获取详细信息容器
|
||||
const detailBox = document.getElementById('progress-detail');
|
||||
|
||||
// 根据N值动态调整每个进度节点的宽度
|
||||
const nodeWidth = 100 / N; // 每个节点的宽度为 100% / N
|
||||
|
||||
// 根据N值生成子框并设置颜色
|
||||
for (let i = 0; i < N; i++) {
|
||||
const titleBox = document.createElement('div');
|
||||
titleBox.className = 'progress-title';
|
||||
|
||||
// 设置进度条的颜色
|
||||
if (i < idx) {
|
||||
titleBox.classList.add('green'); // 已完成部分
|
||||
} else {
|
||||
titleBox.classList.add('white'); // 未完成部分
|
||||
}
|
||||
|
||||
// 设置每个子框的标题
|
||||
titleBox.innerHTML = titles[i] || `Step ${i + 1}`;
|
||||
|
||||
// 设置每个进度节点的宽度
|
||||
titleBox.style.width = `${nodeWidth}%`;
|
||||
|
||||
// 监听鼠标移入事件来显示详情
|
||||
titleBox.addEventListener('mouseenter', function() {
|
||||
detailBox.innerHTML = `Step ${i + 1}: ${titles[i] || "No title"}`;// - Additional details here...`;
|
||||
detailBox.style.display = 'block';
|
||||
// 根据进度条位置显示详情
|
||||
const rect = titleBox.getBoundingClientRect();
|
||||
detailBox.style.top = `${rect.top + window.scrollY - 100}px`; // 微调位置
|
||||
detailBox.style.left = `${rect.left + window.scrollX + rect.width / 2 - detailBox.offsetWidth / 2}px`;
|
||||
});
|
||||
|
||||
// 监听鼠标移出事件来隐藏详情
|
||||
titleBox.addEventListener('mouseleave', function() {
|
||||
detailBox.style.display = 'none';
|
||||
});
|
||||
|
||||
progressBox.appendChild(titleBox);
|
||||
}
|
||||
|
||||
// 将生成的进度条添加到容器中
|
||||
container.appendChild(progressBox);
|
||||
}
|
||||
125
Html/apps/static/js/dashboard.js
Normal file
125
Html/apps/static/js/dashboard.js
Normal file
@@ -0,0 +1,125 @@
|
||||
// dashboard.js
|
||||
let courseData;
|
||||
function show_user_data(user_data, course_brief_data_list){
|
||||
courseData = user_data.course_process_dict
|
||||
for (let i=0;i<course_brief_data_list.length;i++){
|
||||
course_brief_data = course_brief_data_list[i]
|
||||
console.log(course_brief_data)
|
||||
courseData[course_brief_data.course_id].course_id = course_brief_data.course_id;
|
||||
courseData[course_brief_data.course_id].title = course_brief_data.course_name;
|
||||
courseData[course_brief_data.course_id].lessons = course_brief_data.lessons;
|
||||
courseData[course_brief_data.course_id].course_img_path = course_brief_data.course_img_path;
|
||||
courseData[course_brief_data.course_id].course_description = course_brief_data.course_description;
|
||||
courseData[course_brief_data.course_id].course_create_date = course_brief_data.course_create_date;
|
||||
courseData[course_brief_data.course_id].course_update_data = course_brief_data.course_update_data;
|
||||
}
|
||||
for (var course in courseData){
|
||||
courseData[course].chapters = courseData[course].lessons
|
||||
console.log(courseData[course])
|
||||
}
|
||||
|
||||
let courseCardsContainer = document.getElementById('course-cards');
|
||||
courseCardsContainer.innerHTML = "";
|
||||
for (var course in courseData){
|
||||
course_id = course;
|
||||
course = courseData[course];
|
||||
let courseCard = document.createElement('div');
|
||||
|
||||
courseCard.className = 'course-card';
|
||||
courseCard.innerHTML = `
|
||||
<img src="${course.course_img_path}" alt="课程封面", class="course-image">
|
||||
<div class="course-info">
|
||||
<h3>${course.title}</h3>
|
||||
<p>${course.course_description}</p>
|
||||
</div>
|
||||
<button class="select-button" >查看目录</button>
|
||||
`;
|
||||
courseCardsContainer.appendChild(courseCard);
|
||||
courseCard.data = course_id
|
||||
courseCard.addEventListener('click',() => {
|
||||
openCourseProgress(courseCard.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
function openCourseProgress(courseId) {
|
||||
console.log(courseId)
|
||||
const course = courseData[courseId];
|
||||
if (!course) return;
|
||||
|
||||
// 更新右侧滑出卡片的内容
|
||||
document.getElementById('course-title').textContent = course.title;
|
||||
///////////////////////// course.progress;还没有计算
|
||||
document.getElementById('progress').textContent = course.progress;
|
||||
|
||||
// 更新章节列表
|
||||
const chapterList = document.getElementById('chapter-list');
|
||||
chapterList.innerHTML = ''; // 清空之前的章节
|
||||
|
||||
course.chapters.forEach(chapter => {
|
||||
const chapterItem = document.createElement('li');
|
||||
chapterItem.classList.add('chapter-item');
|
||||
|
||||
const chapterTitle = document.createElement('div');
|
||||
chapterTitle.classList.add('chapter-title');
|
||||
chapterTitle.textContent = chapter.lesson_id;
|
||||
chapterItem.appendChild(chapterTitle);
|
||||
|
||||
// 创建子章节
|
||||
if (chapter.subChapters && chapter.subChapters.length > 0) {
|
||||
const subChapterList = document.createElement('ul');
|
||||
subChapterList.classList.add('sub-chapter-list');
|
||||
|
||||
chapter.subChapters.forEach(subChapter => {
|
||||
const subChapterItem = document.createElement('li');
|
||||
subChapterItem.classList.add('sub-chapter-item');
|
||||
subChapterItem.textContent = subChapter;
|
||||
console.log('-------------------')
|
||||
console.log(course)
|
||||
// 查找学生进度
|
||||
for(let i = 0; i < course.lesson_processs.length; i++) {
|
||||
if (course.lesson_processs[i][1] == chapter.lesson_id) {//确定lesson_id对应正确
|
||||
console.log('-------------------')
|
||||
console.log(course.lesson_processs[i][0])
|
||||
lesson_chapters_progress = course.lesson_processs[i][0];//寻找对应的每一个章节的进度
|
||||
for (let j=0; j<lesson_chapters_progress.length;j++){
|
||||
chapter_progress = lesson_chapters_progress[j]
|
||||
if(chapter_progress.title == subChapter){
|
||||
subChapterItem.textContent += ("(已"+(chapter_progress.is_rebuttal?"申辩" : "完成")+" 得分"+ (chapter_progress.is_rebuttal?chapter_progress.rebuttal_score : chapter_progress.score) +")");
|
||||
}
|
||||
}
|
||||
if (course.lessons[i].progress === 1) {
|
||||
subChapterItem.classList.add('completed');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加点击事件跳转到学习页面
|
||||
subChapterItem.addEventListener('click', () => {
|
||||
const courseId = encodeURIComponent(course.course_id); // 对课程名称进行编码
|
||||
const url = `/desktop_nouser/${courseId}/${chapter.lesson_id}`;
|
||||
window.location.href = url; // 跳转到该学习页面
|
||||
});
|
||||
|
||||
subChapterList.appendChild(subChapterItem);
|
||||
});
|
||||
|
||||
chapterItem.appendChild(subChapterList);
|
||||
|
||||
// 添加点击事件切换子章节显示
|
||||
chapterItem.addEventListener('click', () => {
|
||||
chapterItem.classList.toggle('open');
|
||||
});
|
||||
}
|
||||
|
||||
chapterList.appendChild(chapterItem);
|
||||
});
|
||||
|
||||
// 打开滑出卡片
|
||||
document.getElementById('courseProgress').classList.add('open');
|
||||
}
|
||||
|
||||
function closeCourseProgress() {
|
||||
// 关闭滑出卡片
|
||||
document.getElementById('courseProgress').classList.remove('open');
|
||||
}
|
||||
42
Html/apps/static/js/index.js
Normal file
42
Html/apps/static/js/index.js
Normal file
@@ -0,0 +1,42 @@
|
||||
function show_books(courses_data, user_selected_courses){
|
||||
console.log(courses_data)
|
||||
console.log(user_selected_courses)
|
||||
}
|
||||
function show_course_details(course_id){
|
||||
window.location.href = '/course/' + course_id
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const selectButtons = document.querySelectorAll('.select-button');
|
||||
|
||||
selectButtons.forEach(button => {
|
||||
button.addEventListener('click', function(event) {
|
||||
event.stopPropagation(); // 阻止事件冒泡
|
||||
const courseId = this.getAttribute('data-course-id');
|
||||
fetch(`/select_course`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': '{{ csrf_token() }}' // 如果使用 CSRF 保护
|
||||
},
|
||||
body: JSON.stringify({ course_id: courseId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// 更新按钮样式或显示消息
|
||||
this.classList.remove('select-button');
|
||||
this.classList.add('selected-button');
|
||||
this.textContent = '已选择';
|
||||
alert('选择课程成功');
|
||||
} else {
|
||||
alert('选择课程失败');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('选择课程失败');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
87
Html/apps/static/js/login.js
Normal file
87
Html/apps/static/js/login.js
Normal file
@@ -0,0 +1,87 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const switchRoleButton = document.getElementById('switch-role');
|
||||
const loginForm = document.getElementById('login-form');
|
||||
const usernameLabel = document.getElementById('username-label');
|
||||
const usernameInput = document.getElementById('username');
|
||||
const passwordInput = document.getElementById('password');
|
||||
const registerLinkHref = document.getElementById('register-link-href');
|
||||
|
||||
let isTeacherLogin = false;
|
||||
|
||||
// 切换角色按钮点击事件
|
||||
switchRoleButton.addEventListener('click', function() {
|
||||
isTeacherLogin = !isTeacherLogin; // 切换状态
|
||||
toggleButtonColor(isTeacherLogin);
|
||||
toggleLoginFields(isTeacherLogin);
|
||||
});
|
||||
// 根据角色切换按钮背景色
|
||||
function toggleButtonColor(isTeacher) {
|
||||
if (isTeacher) {
|
||||
loginForm.classList.add('teacher-login');
|
||||
} else {
|
||||
loginForm.classList.remove('teacher-login');
|
||||
}
|
||||
}
|
||||
// 切换显示不同的表单字段
|
||||
function toggleLoginFields(isTeacher) {
|
||||
if (isTeacher) {
|
||||
// 显示教师登录字段
|
||||
usernameLabel.textContent = '教师用户名';
|
||||
switchRoleButton.textContent = '切换到学生登录'; // 更新按钮文本
|
||||
registerLinkHref.href = '/register_teacher';
|
||||
registerLinkHref.textContent = '注册新教师账号';
|
||||
} else {
|
||||
// 显示学生登录字段
|
||||
usernameLabel.textContent = '学生用户名';
|
||||
switchRoleButton.textContent = '切换到教师登录'; // 更新按钮文本
|
||||
registerLinkHref.href = '/register';
|
||||
registerLinkHref.textContent = '注册新学生账号';
|
||||
}
|
||||
}
|
||||
|
||||
// 处理登录提交
|
||||
loginForm.addEventListener('submit', function(event) {
|
||||
event.preventDefault(); // 防止默认提交
|
||||
|
||||
const username = usernameInput.value.trim();
|
||||
const password = passwordInput.value.trim();
|
||||
|
||||
if (!username || !password) {
|
||||
alert('请填写所有必需的字段');
|
||||
return;
|
||||
}
|
||||
|
||||
// 登录请求的 URL 依据角色不同而不同
|
||||
const loginUrl = isTeacherLogin ? '/login_teacher_post' : '/login_post';
|
||||
|
||||
const data = isTeacherLogin ? { username, password } : { username, password };
|
||||
|
||||
// 发送登录请求
|
||||
fetch(loginUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data) // 将数据发送到后端
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// 登录成功,跳转到主页
|
||||
if (isTeacherLogin) {
|
||||
window.location.href = '/teacherboard';
|
||||
} else {
|
||||
window.location.href = '/dashboard';
|
||||
}
|
||||
} else {
|
||||
// 登录失败,提示错误信息
|
||||
alert('登录失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('登录请求失败,请稍后重试');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
39
Html/apps/static/js/register.js
Normal file
39
Html/apps/static/js/register.js
Normal file
@@ -0,0 +1,39 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const registerForm = document.getElementById('register-form');
|
||||
|
||||
registerForm.addEventListener('submit', function(event) {
|
||||
event.preventDefault(); // 阻止表单默认提交行为
|
||||
|
||||
const username = document.getElementById('username').value;
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
const confirmPassword = document.getElementById('confirm-password').value;
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
alert('密码和确认密码不一致');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('/register_post', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': '{{ csrf_token() }}' // 如果使用 CSRF 保护
|
||||
},
|
||||
body: JSON.stringify({ username, email, password })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('注册成功');
|
||||
window.location.href = '/login'; // 注册成功后跳转到登录页面
|
||||
} else {
|
||||
alert('注册失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('注册失败');
|
||||
});
|
||||
});
|
||||
});
|
||||
41
Html/apps/static/js/register_teacher.js
Normal file
41
Html/apps/static/js/register_teacher.js
Normal file
@@ -0,0 +1,41 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const registerTeacherForm = document.getElementById('register-teacher-form');
|
||||
|
||||
registerTeacherForm.addEventListener('submit', function(event) {
|
||||
event.preventDefault(); // 阻止表单默认提交行为
|
||||
|
||||
const username = document.getElementById('teacher-username').value;
|
||||
const email = document.getElementById('teacher-email').value;
|
||||
const password = document.getElementById('teacher-password').value;
|
||||
const confirmPassword = document.getElementById('teacher-confirm-password').value;
|
||||
|
||||
// 检查密码和确认密码是否一致
|
||||
if (password !== confirmPassword) {
|
||||
alert('密码和确认密码不一致');
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用 Fetch API 发送注册请求
|
||||
fetch('/register_teacher_post', { // 教师注册路由
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': '{{ csrf_token() }}' // 如果使用 CSRF 保护
|
||||
},
|
||||
body: JSON.stringify({ username, email, password }) // 发送数据
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('教师注册成功');
|
||||
window.location.href = '/login'; // 注册成功后跳转到登录页面
|
||||
} else {
|
||||
alert('注册失败: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('注册失败');
|
||||
});
|
||||
});
|
||||
});
|
||||
189
Html/apps/static/js/teacherboard.js
Normal file
189
Html/apps/static/js/teacherboard.js
Normal file
@@ -0,0 +1,189 @@
|
||||
function lessonTemplate(lesson) {
|
||||
return `
|
||||
<li class="lesson-item">
|
||||
<span class="lesson-text" onclick="editLesson('${lesson}')">${lesson}
|
||||
<button class="icon-btn edit-btn" onclick="editLesson('${lesson}')">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
</span>
|
||||
<button class="icon-btn delete-btn" onclick="deleteLesson('${lesson}')">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</li>
|
||||
`;
|
||||
}
|
||||
|
||||
function show_teacher_data(user_data, user_course_data) {
|
||||
// 这里可以根据user_course_data生成课程卡片
|
||||
const courseCardsContainer = document.getElementById('course-cards');
|
||||
user_course_data.forEach(course => {
|
||||
const courseCard = document.createElement('div');
|
||||
courseCard.classList.add('course-card');
|
||||
courseCard.onclick = function() { openCourseDetails(course.id); };
|
||||
courseCard.innerHTML = `
|
||||
<img src="${course.cover_image}" alt="课程封面" class="course-image">
|
||||
<div class="course-info">
|
||||
<h3 class="course-name">${course.name}</h3>
|
||||
<p class="course-description">${course.description}</p>
|
||||
</div>
|
||||
`;
|
||||
courseCardsContainer.appendChild(courseCard);
|
||||
});
|
||||
}
|
||||
let isAddingChapter = false;
|
||||
|
||||
function showInputForNewChapter() {
|
||||
if (isAddingChapter) return; // 防止重复点击
|
||||
|
||||
isAddingChapter = true; // 标记正在添加章节
|
||||
|
||||
// 找到新增章节按钮并隐藏
|
||||
const addButton = document.querySelector('.add-chapter-btn');
|
||||
addButton.style.display = 'none';
|
||||
|
||||
// 创建一个输入框
|
||||
const input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.placeholder = '请输入章节名称...';
|
||||
input.className = 'new-chapter-input';
|
||||
input.onblur = () => checkAndAddChapter(input);
|
||||
|
||||
// 将输入框插入到页面
|
||||
const chapterList = document.getElementById('chapter-list');
|
||||
chapterList.appendChild(input);
|
||||
input.focus(); // 聚焦到输入框
|
||||
}
|
||||
|
||||
function checkAndAddChapter(input) {
|
||||
const chapterName = input.value.trim();
|
||||
|
||||
// 如果章节名称为空,显示提示并不添加
|
||||
if (!chapterName) {
|
||||
input.remove(); // 删除输入框
|
||||
document.querySelector('.add-chapter-btn').style.display = 'block'; // 重新显示新增章节按钮
|
||||
isAddingChapter = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果章节名称合法,添加到章节列表
|
||||
const chapterList = document.getElementById('chapter-list');
|
||||
const chapterItem = document.createElement('li');
|
||||
chapterItem.innerHTML = `
|
||||
<li class="lesson-item">
|
||||
<strong>${chapterName}</strong> <button class="icon-btn delete-btn" onclick="deleteChapter(this)">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</li>
|
||||
<ul>
|
||||
</ul>
|
||||
<button class="add-lesson-btn" onclick="showInputForNewLesson('${chapterName}', this)">新增课时</button>
|
||||
|
||||
`;
|
||||
chapterList.appendChild(chapterItem);
|
||||
// 恢复新增按钮的显示
|
||||
document.querySelector('.add-chapter-btn').style.display = 'block';
|
||||
input.remove();
|
||||
isAddingChapter = false;
|
||||
}
|
||||
function openCourseDetails(courseId) {
|
||||
// 打开课程目录
|
||||
const courseDetails = document.getElementById('courseDetails');
|
||||
const courseTitle = document.getElementById('course-title');
|
||||
courseTitle.textContent = "课程名称: " + courseId; // 假设这里显示课程ID,实际情况应该是课程名称
|
||||
|
||||
courseDetails.classList.add('open');
|
||||
|
||||
// 获取章节数据并渲染
|
||||
renderChapters(courseId);
|
||||
}
|
||||
function deleteChapter(deleteButton) {
|
||||
// 删除章节
|
||||
const chapterItem = deleteButton.closest('li');
|
||||
chapterItem.remove();
|
||||
}
|
||||
function renderChapters(courseId) {
|
||||
const chapterList = document.getElementById('chapter-list');
|
||||
chapterList.innerHTML = ""; // 清空章节列表
|
||||
|
||||
// 假设从服务器获取课程章节数据
|
||||
const chapters = [
|
||||
{ title: "第一章:算法基础", lessons: ["算法简介", "算法设计方法"] },
|
||||
{ title: "第二章:数据结构", lessons: ["数组", "链表"] }
|
||||
];
|
||||
|
||||
chapters.forEach(chapter => {
|
||||
const chapterItem = document.createElement('li');
|
||||
|
||||
// 渲染章节标题
|
||||
let lessonsHtml = chapter.lessons.map(lesson => lessonTemplate(lesson)).join('');
|
||||
|
||||
chapterItem.innerHTML = `
|
||||
<strong>${chapter.title}</strong>
|
||||
<ul>
|
||||
${lessonsHtml}
|
||||
</ul>
|
||||
<button class="add-lesson-btn" onclick="showInputForNewLesson('${chapter.title}', this)">新增课时</button>
|
||||
`;
|
||||
|
||||
|
||||
chapterList.appendChild(chapterItem);
|
||||
});
|
||||
}
|
||||
|
||||
function showInputForNewLesson(chapterTitle, button) {
|
||||
// 防止重复点击
|
||||
const addButton = button;
|
||||
addButton.style.display = 'none'; // 隐藏按钮
|
||||
|
||||
// 创建一个输入框
|
||||
const input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.placeholder = '请输入课时名称...';
|
||||
input.className = 'new-lesson-input';
|
||||
input.onblur = () => checkAndAddLesson(input, chapterTitle, addButton); // 失去焦点时检查输入
|
||||
|
||||
// 将输入框插入到章节列表中
|
||||
const chapterItem = addButton.closest('li'); // 获取到点击按钮的父元素
|
||||
chapterItem.appendChild(input);
|
||||
input.focus(); // 聚焦到输入框
|
||||
}
|
||||
function checkAndAddLesson(input, chapterTitle, addButton) {
|
||||
const lessonName = input.value.trim();
|
||||
|
||||
// 如果课时名称为空,显示提示并不添加
|
||||
if (!lessonName) {
|
||||
input.remove(); // 删除输入框
|
||||
addButton.style.display = 'block'; // 重新显示新增课时按钮
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果课时名称合法,添加到课时列表
|
||||
const chapterList = document.getElementById('chapter-list');
|
||||
const chapterItem = Array.from(chapterList.children).find(item => item.querySelector('strong').textContent === chapterTitle);
|
||||
const lessonsList = chapterItem.querySelector('ul');
|
||||
|
||||
const lessonItem = document.createElement('span');
|
||||
lessonItem.innerHTML = lessonTemplate(lessonName);
|
||||
|
||||
lessonsList.appendChild(lessonItem); // 将新课时添加到章节下
|
||||
input.remove(); // 删除输入框
|
||||
addButton.style.display = 'block'; // 重新显示新增课时按钮
|
||||
}
|
||||
function deleteLesson(lesson) {
|
||||
const lessonItems = document.querySelectorAll('.lesson-item');
|
||||
lessonItems.forEach(item => {
|
||||
if (item.querySelector('.lesson-text').textContent === lesson) {
|
||||
item.remove(); // 删除对应的课时项
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function editLesson(lesson) {
|
||||
// 编辑课时的逻辑
|
||||
alert("编辑课时: " + lesson);
|
||||
}
|
||||
|
||||
function closeCourseDetails() {
|
||||
document.getElementById('courseDetails').classList.remove('open');
|
||||
}
|
||||
52
Html/apps/static/twice_split.html
Normal file
52
Html/apps/static/twice_split.html
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>二分查找与二分答案</h1>
|
||||
<h2>二分查找</h2>
|
||||
<h3>引入</h3>
|
||||
<p>二分是一个很简单基础,但很重要的知识点,为以后许多高级的数据结构与算法铺垫。</p>
|
||||
<p>下面是一个用二分的简单场景:</p>
|
||||
<p>假设小明从0到1000之间选择了一个数字但不告诉你,你可以不断猜测这个数,每次猜测小明会告知你的猜测得过大还是过小,问最多几次就一定能猜中?</p>
|
||||
<p>答案是利用二分查找的原理,猜测11次即可。</p>
|
||||
<ol>
|
||||
<li>对于0到1000的答案备选区,猜测中位数500,假设过小,</li>
|
||||
<li>则对于501到1000的答案备选区,猜测750,假设过大</li>
|
||||
<li>则对于501到749的答案备选区,猜测625,假设过小,</li>
|
||||
<li>则对于626到749区间......</li>
|
||||
<li>(688-749)</li>
|
||||
<li>(718-749)</li>
|
||||
<li>(734-749)</li>
|
||||
<li>(742-749)</li>
|
||||
<li>(746-749)</li>
|
||||
<li>(748-749)</li>
|
||||
<li>(749-749)</li>
|
||||
</ol>
|
||||
<p>在最差的情况下,第11次的答案备选区就一定长度为1了,也就是必然是答案。</p>
|
||||
<p>因此如果序列是有序的,就可以通过二分查找快速定位所需要的数据。</p>
|
||||
<h4>思考题(询问Agent以学习计算方法,或验证你的答案)</h4>
|
||||
<p>对于上面那个题目,如果问题区间是1到4000,最差情况下需要猜测几次?</p>
|
||||
<h3>练习:二分查找</h3>
|
||||
<p>试试对于下面的题目,用代码实现一下二分查找。</p>
|
||||
<h4>题目:有序数组寻址</h4>
|
||||
<p>给出一个长度为n的有序数组(从小到大),有q次询问,对于每次询问,输出指定数在数组中的下标。如果不存在则输出-1。</p>
|
||||
<h5>输入</h5>
|
||||
<p>第一行一个整数n。(1<=n<=10^5)</p>
|
||||
<p>第二行n个用空格分开的整数ai。(0<=ai<=10^8)</p>
|
||||
<p>第三行一个整数q,表示询问的次数。(1<=q<=10^4)</p>
|
||||
<p>后q行,每行一个整数b,表示询问的数。(0<=b<=10^8)</p>
|
||||
<h5>输出</h5>
|
||||
<p>q行,每行一个整数,对应每次询问的返回结果。</p>
|
||||
<h5>提示:</h5>
|
||||
<p>完成代码后,通知Agent进行评测。</p>
|
||||
<p>如果你还不完全会这个算法,询问Agent获取提示并进行学习。</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user