灵感
给工人发工资是按小时计算的,每次都要上网,我比较喜欢用 Hours Calculator ,也喜欢它的其它的功能, 做个类似的。
我以为是 Python,结果在学 javascript 看 HTML,页面的基础还停留在 Frontpage 2000 因为 MS-Office 2000 里有的。
忽略我的美学... 已排版尽力
这是一个长期的项目当遇到生活计算时,就会添加进来,也许会吧
时间换算器 Time Conversion Calculator
目录结构
/11. Calculator
/static
- styles.css
/workhours
- workhourscal.js
/time
- timercal.js
/templates
- index.html
/converters
- time.html
- workhours.html
- app.py
服务端
app.py
当前代码
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/converters/time')
def time_converter():
# 渲染位于 templates/converters/time.html 的模板
return render_template('converters/time.html')
@app.route('/converters/workhours')
def work_hours():
return render_template('converters/workhours.html')
if __name__ == '__main__':
app.run(debug=True)
说明:Flask 程序应用代码
从 Flask 导入必要的模块: render_template 用于呈现 HTML 模板。
Flask 应用程序初始化: app = Flask(__name__)
在不指定 IP 与端口的默认情况下是 http://127.0.0.1:5000
路由定义: 在这里可以看出,程序的目录结构
@app.route('/')
def index():
return render_template('index.html')
@app.route('/') 装饰器将根 URL '/' 映射到 index() 函数,该函数从 templates 目录呈现 index.html
@app.route('/converters/time')
def time_converter():
# 渲染位于 templates/converters/time.html 的模板
return render_template('converters/time.html')
@app.route('/converters/time') 装饰器将 URL '/converters/time' 映射到 time_converter() 函数,该函数呈现位于 templates/converters 目录中的 time.html
@app.route('/converters/workhours')
def work_hours():
return render_template('converters/workhours.html')
@app.route('/converters/workhours') 装饰器将 URL '/converters/workhours' 映射到 work_hours() 函数,该函数呈现位于 templates/converters 目录中的 workhours.html
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主页 - 单位换算工具</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f4f4;
}
.tools-list {
list-style: none;
padding: 0;
}
.tools-list li {
margin-bottom: 10px;
}
.tools-list a {
display: flex;
flex-direction: column;
align-items: start;
gap: 10px;
text-decoration: none;
font-size: 1.2em;
color: #007BFF;
border: 1px solid #007BFF;
padding: 10px 15px;
border-radius: 5px;
transition: background-color 0.3s, color 0.3s;
}
.tools-list a:hover {
background-color: #007BFF;
color: white;
}
.tools-list li {
margin-bottom: 20px; /* 增加底部外边距 */
}
</style>
</head>
<body>
<h1>单位换算工具</h1>
<p>请选择一个单位换算工具:</p>
<ul class="tools-list">
<li><a href="{{ url_for('time_converter') }}">时间换算器</a></li>
<li><a href="{{ url_for('work_hours') }}">工作小时计算器</a></li>
<!-- 可以在这里添加更多链接到其他转换工具 -->
</ul>
</body>
</html>
还在练手,离美有很大距离。
<body>
<h1>单位换算工具</h1>
<p>请选择一个单位换算工具:</p>
<ul class="tools-list">
<li><a href="{{ url_for('time_converter') }}">时间换算器</a></li>
<li><a href="{{ url_for('work_hours') }}">工作小时计算器</a></li>
<!-- 可以在这里添加更多链接到其他转换工具 -->
</ul>
</body>
说明:使用 Flask 的 url_for 函数来引用静态文件
引用 app.py 与 index.html 里面的代码:
@app.route('/converters/time')
def time_converter():
# 渲染位于 templates/converters/time.html 的模板
return render_template('converters/time.html')
<a href="{{ url_for('time_converter') }}">时间换算器</a>
在 Flask 中使用 url_for() 函数时,如上面,该函数的参数 'time_converter' 是 Flask 路由装饰器 @app.route('/converters/time') 中定义的视图函数的名称:def time_converter
render_template 函数调用的路径 ('converters/time.html') 是 templates 文件夹的子文件夹 converters 中的 time.html 文件。
time.html
当前代码
<!DOCTYPE html>
<!--time.html-->>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>时间换算器</title>
<!-- 使用 Flask 的 url_for 函数来引用静态文件 -->
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f4f4;
}
/* 右上角导航按钮 */
.nav-buttons {
position: absolute;
top: 20px;
right: 20px;
}
.nav-buttons a, .nav-buttons button {
text-decoration: none;
font-size: 0.9em;
color: white;
background-color: #007BFF;
border: none;
padding: 8px 15px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
margin-left: 10px;
}
.nav-buttons a:hover, .nav-buttons button:hover {
background-color: #0056b3;
}
.nav-buttons button {
font-size: 0.9em;
}
h1, h2 {
text-align: center;
color: #333;
}
.content {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 20px;
}
.calculator-container {
flex: 1;
min-width: 300px;
background: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
}
.description {
flex: 2;
min-width: 500px;
background: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
margin-top: 40px;
}
table {
width: 33%;
margin: 0 auto;
border-collapse: collapse;
margin-top: 20px;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
text-align: center;
padding: 8px;
font-size: 1.1rem;
}
th {
background-color: #f0f0f0;
}
.sidereal {
margin-top: 40px;
font-size: 0.9rem;
line-height: 1.6;
}
.references {
margin-top: 20px;
font-size: 0.85rem;
}
.references a {
color: blue;
text-decoration: none;
}
.boxed-container {
border: 1px solid #87CEEB;
padding: 10px;
background-color: #f0f8ff;
border-radius: 10px;
box-shadow: 3px 3px 15px rgba(135, 206, 235, 0.5);
margin-bottom: 20px;
}
.styled-input {
padding: 10px;
width: 100%;
margin-top: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 1.1em;
box-sizing: border-box;
}
.unit-buttons {
margin: 10px 0;
}
.unit-btn {
padding: 10px 20px;
margin: 5px;
background-color: #f0f0f0;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.unit-btn.active {
background-color: #87CEEB;
border-color: #007BFF;
color: white;
}
.unit-btn:hover {
background-color: #ddd;
}
.clear-btn {
/*margin-top: 20px;
margin-bottom: 10px;*/
padding: 15px 30px;
font-size: 1.2em;
background-color: #ff4c4c;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
justify-content:space-between ;
}
.clear-btn:hover {
background-color: #ff3333;
}
th, td {
white-space: nowrap;
}
.table-section-title {
font-size: 1.5em;
font-weight: bold;
color: #333;
margin-top: 40px;
text-align: center;
}
.conversion-table {
width: 33%;
margin: 0 auto;
border-collapse: collapse;
margin-top: 20px;
margin-bottom: 40px;
}
.conversion-table th, .conversion-table td {
border: 1px solid #ddd;
padding: 12px;
text-align: center;
}
.conversion-table th {
background-color: #f0f8ff;
font-weight: bold;
font-size: 1.2em;
}
.conversion-table td {
font-size: 1em;
}
.conversion-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.conversion-table tr:nth-child(odd) {
background-color: #ffffff;
}
h1 {
text-align: left;
color: #333;
font-size: 2em;
margin: 10px 0;
}
h2.rendered {
background: linear-gradient(90deg, #87CEEB, #4b79a1);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 2em;
font-weight: bold;
text-align: center;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
margin: 10px 0;
padding: 10px;
display: inline-block;
width: 100%;
}
label, .styled-input {
margin-top: 10px;
margin-bottom: 10px;
}
label[for="input_value"] {
font-size: 1.5em;
font-weight: bold;
color: #000000;
display: block;
margin-bottom: 10px;
}
.formatted-result {
text-align: center; /* 水平居中 */
font-size: 1.5em; /* 适当调整字体大小 */
font-weight: normal; /* 粗体显示 */
margin: 10px 0; /* 上下增加一些间距 */
}
.button-container {
display: flex;
justify-content: right;
margin: auto;
}
</style>
</head>
<body>
<!-- 顶部导航按钮 -->
<div class="nav-buttons">
<!-- 返回上一页 -->
<button onclick="history.back()">返回上一页</button>
<!-- 返回主页 -->
<a href="{{ url_for('index') }}">返回主页</a>
</div>
<!-- 内容区 -->
<div class="content">
<!-- 左侧的计算器容器 -->
<div class="calculator-container boxed-container">
<h2 class="rendered">时间单位转换器</h2>
<!-- 改为"从"并统一输入框风格 -->
<label for="input_value">从:</label>
<input type="number" id="input_value" class="styled-input" oninput="convertTime()" required>
<!-- 单位选择按钮 -->
<div class="unit-buttons">
<button type="button" class="unit-btn" onclick="selectUnit('nanoseconds')">纳秒</button>
<button type="button" class="unit-btn" onclick="selectUnit('microseconds')">微秒</button>
<button type="button" class="unit-btn" onclick="selectUnit('milliseconds')">毫秒</button>
<button type="button" class="unit-btn" onclick="selectUnit('seconds')">秒</button>
<button type="button" class="unit-btn" onclick="selectUnit('minutes')">分</button>
<button type="button" class="unit-btn" onclick="selectUnit('hours')">时</button>
<button type="button" class="unit-btn" onclick="selectUnit('days')">天</button>
<button type="button" class="unit-btn" onclick="selectUnit('weeks')">周</button>
<button type="button" class="unit-btn" onclick="selectUnit('months')">月</button>
<button type="button" class="unit-btn" onclick="selectUnit('years')">年</button>
</div>
<div class="button-container">
<button class="clear-btn" onclick="clearFields()">清除</button>
</div>
<div>
<h2>到:</h2>
<table>
<thead>
<tr>
<th>单位</th>
<th>换算值</th>
</tr>
</thead>
<tbody>
<tr>
<td>纳秒</td>
<td><span id="result_nanoseconds">0.00</span> 纳秒</td>
</tr>
<tr>
<td>微秒</td>
<td><span id="result_microseconds">0.00</span> 微秒</td>
</tr>
<tr>
<td>毫秒</td>
<td><span id="result_milliseconds">0.00</span> 毫秒</td>
</tr>
<tr>
<td>秒</td>
<td><span id="result_seconds">0.00</span> 秒</td>
</tr>
<tr>
<td>分钟</td>
<td><span id="result_minutes">0.00</span> 分钟</td>
</tr>
<tr>
<td>小时</td>
<td><span id="result_hours">0.00</span> 小时</td>
</tr>
<tr>
<td>天</td>
<td><span id="result_days">0.00</span> 天</td>
</tr>
<tr>
<td>周</td>
<td><span id="result_weeks">0.00</span> 周</td>
</tr>
<tr>
<td>月</td>
<td><span id="result_months">0.00</span> 月</td>
</tr>
<tr>
<td>年</td>
<td><span id="result_years">0.00</span> 年</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 右侧的说明文字 -->
<div class="description">
<h2>单位换算说明</h2>
<p>输入您想要转换的时间值和单位,然后选择您要转换成的时间单位。您可以在秒 (seconds)、毫秒 (milliseconds)、微秒 (microseconds)、纳秒 (nanoseconds)、天 (days)、小时 (hours)、周 (weeks)、月 (months) 和年 (years) 之间进行转换。</p>
<p>在这个时间转换计算器中,月的计算使用平均每月30.416天。这个值等于每年365天除以每年12个月。365 ÷ 12 = 每月30.416天。</p>
<p>在这个时间转换器中,年的计算为每年365天。此计算器不考虑闰年中的额外一天(闰年每年有366天)。</p>
<h3>如何转换时间单位</h3>
<p>您可以使用转换因数通过乘法或除法将一个时间单位转换为另一个时间单位。通过了解转换因数,转换单位可以变成一个简单的数学问题:</p>
<p><strong>S * C = E</strong></p>
<p>其中 <strong>S</strong> 为起始值,<strong>C</strong>为转换因子,<strong>E</strong>为转换结果</p>
<h4>秒的转换</h4>
<p>下表包含将任何时间值转换为秒的转换因数,使用乘法即可完成转换。</p>
<p><strong>示例:</strong> 将120分钟转换为秒</p>
<p>将120分钟乘以每分钟60秒:120 分钟 * 60 秒/分钟 = 7200 秒</p>
<p><strong>示例:</strong> 将28,800秒转换为小时</p>
<p>将28,800秒乘以每秒1/3600小时:这与将28,800秒除以每小时3600秒相同:</p>
<p>28,800 秒 ÷ 3600 秒/小时 = 8 小时</p>
<p>要在左列中的任何单位之间进行转换,例如从 A 转换为 B,您可以乘以 A 的系数以将 A 转换为秒,然后除以 B 的系数以转换出秒。或者,您可以通过将 A 的转换系数除以 B 的转换系数来找到简化的系数。</p>
<p>要将分钟转换为小时,请将分钟数乘以 60,然后除以 3600。简化后,这相当于乘以 60/3600,即 0.016666667。要直接从分钟转换为小时,请乘以 0.016。</p>
</div>
</div>
<!-- 单位、符号和转换值表格 -->
<h2 class="table-section-title">单位、符号和转换值</h2>
<table class="conversion-table">
<thead>
<tr>
<th>单位</th>
<th>符号</th>
<th>转换为秒的乘数</th>
</tr>
</thead>
<tbody>
<tr><td>纳秒</td><td>ns</td><td>0.000000001 秒的十亿分之一</td></tr>
<tr><td>微秒</td><td>ms</td><td>0.000001 秒的百万分之一</td></tr>
<tr><td>毫秒</td><td>ms</td><td>0.001 秒的千分之一</td></tr>
<tr><td>秒</td><td>s</td><td>1</td></tr>
<tr><td>秒(恒星)</td><td>s</td><td>0.99726956</td></tr>
<tr><td>分钟</td><td>min</td><td>60</td></tr>
<tr><td>分钟(恒星)</td><td>min</td><td>59.83617361</td></tr>
<tr><td>小时</td><td>h</td><td>3600</td></tr>
<tr><td>小时(恒星)</td><td>h</td><td>3590.170417</td></tr>
<tr><td>天</td><td>d</td><td>86400</td></tr>
<tr><td>天(恒星)</td><td>d</td><td>86164.09</td></tr>
<tr><td>周</td><td>wk</td><td>604800</td></tr>
<tr><td>月</td><td>mo</td><td>2628000</td></tr>
<tr><td>shake</td><td>shake</td><td>0.00000001</td></tr>
<tr><td>年</td><td>yr</td><td>31536000</td></tr>
<tr><td>年(恒星)</td><td>yr</td><td>31449892.85</td></tr>
<tr><td>十年</td><td>dec</td><td>315360000</td></tr>
<tr><td>世纪</td><td>c</td><td>3153600000</td></tr>
<tr><td>千年</td><td></td><td>31536000000</td></tr>
</tbody>
</table>
<div class="sidereal">
<h3>恒星日 (Sidereal Day)</h3>
<p>恒星日:天文学中使用的时间单位,相当于地球相对于恒星完成一次旋转的时间。如果我们可以从太阳系外观察地球,我们会看到它在一年内实际完成了 366.242 次旋转(即绕太阳一圈)。我们只计算 365.242 次旋转,因为我们绕太阳公转时其中一次旋转被抵消。因此,恒星日比平均太阳日短 1/366.242。恒星日等于 23 小时 56 分 4.090 54 秒,或 86164.090 54 秒。</p>
<p><strong>为什么恒星日比太阳日短?</strong><br>
这是因为地球不仅在自转,还围绕太阳公转。当地球自转一圈时,它也在围绕太阳前进了一小段路,因此地球需要再多旋转一点,太阳才会回到天空中原来的位置。这就是为什么太阳日比恒星日长大约4分钟的原因。</p>
<p><strong>应用:</strong><br>
恒星日的概念在天文学中有着重要的应用,特别是在精确测量天体的位置和运动时。因为恒星日更加接近地球自转的真实周期,天文观测使用恒星日来追踪天体的变化。</p>
<p>总的来说,恒星日是相对于远处恒星的一天,时间大约是23小时56分钟,稍短于我们常用的太阳日。</p>
</div>
<div class="references">
<p>资料来源:<a href="http://www.ibiblio.org/units/" target="_blank">How Many? A Dictionary of Units of Measurement</a> 访问日期:2023-07-25。</p>
<h3>参考资料/进一步阅读</h3>
<p>The National Institute of Standards and Technology (NIST) -
<a href="https://www.nist.gov/physical-measurement-laboratory/special-publication-811" target="_blank" rel="noopener">
<em>The NIST Guide for the Use of the International System of Units</em>
</a> - Appendix B, subsections
<a href="https://www.nist.gov/physical-measurement-laboratory/nist-guide-si-appendix-b8" target="_blank" rel="noopener">
B.8 Factors for Units Listed Alphabetically
</a> and
<a href="https://www.nist.gov/pml/nist-guide-si-appendix-b9-factors-units-listed-kind-quantity-or-field-science" target="_blank" rel="noopener">
B.9 Factors for units listed by kind of quantity or field of science
</a>.
</p>
<p>Lide, David R., Daniel (Editor-in-Chief).
<em><a href="https://books.google.com/books/about/CRC_Handbook_of_Chemistry_and_Physics_89.html?id=KACWPwAACAAJ" target="_blank" rel="noopener">
CRC Handbook of Chemistry and Physics, 89th Edition</a></em>, New York, NY: CRC Press, p. 1-28, 2008.
</p>
<p>Wikipedia contributors. "Conversion of units" Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, last visited 26 Jun. 2011.
<a href="https://en.wikipedia.org/wiki/Conversion_of_units" target="_blank" rel="noopener">Read more on Wikipedia</a>.
</p>
</div>
<script src="{{ url_for('static', filename='time/timercal.js') }}"></script>
</body>
</html>
说明:
CSS 没有分开, 刚刚还没整明白 “清除” 按钮 怎么 能放在 “到:” 同行最右侧。
同上,这里也用到 url_for('static', filename='time/timercal.js') 函数去调用 javascript 文件 timercal.js ,为什么? static 目录不在 template 里面?
在 Flask 框架中,url_for()函数是用来生成 URL 的,这其中包括静态文件的 URL。当使用 url_for('static', filename='time/timercal.js'),Flask 会自动构建出一个指向应用的静态文件夹中名为 time/timercal.js 的文件的 URL。这里的 'static' 是预设用于引文件夹中内容的。
timercal.js
当前代码
// JavaScript文件:timercal.js
// 初始默认选中的单位是'秒'
let selectedUnit = 'seconds';
// 根据输入值和选定的单位转换时间
function convertTime() {
const inputValue = parseFloat(document.getElementById('input_value').value) || 0;
let totalSeconds = 0;
// 根据选定的单位将输入值转换为总秒数
switch (selectedUnit) {
case 'nanoseconds':
totalSeconds = inputValue / 1000000000;
break;
case 'microseconds':
totalSeconds = inputValue / 1000000;
break;
case 'milliseconds':
totalSeconds = inputValue / 1000;
break;
case 'seconds':
totalSeconds = inputValue;
break;
case 'minutes':
totalSeconds = inputValue * 60;
break;
case 'hours':
totalSeconds = inputValue * 3600;
break;
case 'days':
totalSeconds = inputValue * 86400;
break
case 'weeks':
totalSeconds = inputValue * 604800;
break;
case 'months':
totalSeconds = inputValue * 86400 * 30.44; // 使用月平均天数来近似
break;
case 'years':
totalSeconds = inputValue * 86400 * 365.25; // 考虑闰年的平均秒数
break;
}
// 从总秒数计算所有单位的结果
const results = calculateTimeComponents(totalSeconds);
updateUI(results);
}
// 从秒数计算时间各组成部分
function calculateTimeComponents(seconds) {
return {
nanoseconds: seconds * 1000000000,
microseconds: seconds * 1000000,
milliseconds: seconds * 1000,
seconds: seconds,
minutes: seconds / 60,
hours: seconds / 3600,
days: seconds / 86400,
weeks: seconds / (86400 * 7),
months: seconds / (86400 * 30.44),
years: seconds / (86400 * 365.25)
};
}
function updateUI(results) {
document.getElementById('result_nanoseconds').textContent = results.nanoseconds.toFixed(2) ;
document.getElementById('result_microseconds').textContent = results.microseconds.toFixed(2) ;
document.getElementById('result_milliseconds').textContent = results.milliseconds.toFixed(2) ;
document.getElementById('result_seconds').textContent = results.seconds.toFixed(2) ;
document.getElementById('result_minutes').textContent = results.minutes.toFixed(2) ;
document.getElementById('result_hours').textContent = results.hours.toFixed(2);
document.getElementById('result_days').textContent = results.days.toFixed(2);
document.getElementById('result_weeks').textContent = results.weeks.toFixed(2);
document.getElementById('result_months').textContent = results.months.toFixed(2);
document.getElementById('result_years').textContent = results.years.toFixed(2);
}
// 设置选定的单位并突出显示活动按钮
function selectUnit(unit) {
selectedUnit = unit;
const buttons = document.querySelectorAll('.unit-btn');
buttons.forEach(btn => {
btn.classList.remove('active');
if (btn.textContent.toLowerCase().includes(unit)) {
btn.classList.add('active');
}
});
convertTime(); // 使用新单位重新计算
}
// 清除所有字段并重置输出
function clearFields() {
document.getElementById('input_value').value = '';
convertTime(); // 重新计算以显示零值
}
FLASK 知识分享
Flask 的静态文件与模板的区别:
静态文件(Static Files):
静态文件通常包括 JavaScript 文件、CSS 文件和图片等,这些文件内容不会经常变化。
Flask 默认从项目根目录中的 static
文件夹中服务这些文件。
使用 url_for('static', filename='...')
来生成静态文件的 URL,确保无论应用部署在何种路径或服务器上,文件路径都是正确的。
模板文件(Template Files):
模板文件主要是 HTML 文件,允许动态内容的插入。
Flask 默认从项目根目录中的 templates
文件夹中加载这些模板文件。
模板文件通过 Flask 的 render_template
函数进行调用,并不直接通过 URL 访问。
为什么要分开管理静态文件和模板文件?
- 结构清晰:将静态文件和模板文件分开存放,可以使项目结构更加清晰和有序。静态文件通常被直接发送到客户端而不需服务器处理,而模板文件则需要服务器解析后再发送到客户端。
- 性能优化:静态文件可以通过 Web 服务器(如 Nginx 或 Apache)直接高效地服务,而不需要经过 Flask 处理。这可以减轻 Flask 应用的负载并提高响应速度。
- 安全性:避免直接通过 URL 访问到应用的后端逻辑和模板文件,增强应用的安全性。