updated: on 3Apirl2025
修改/添加 metric_converter , 现为:美制&公制单位转换器 输入数字,点击或回车来获取值,原:长度单位换算 被代换
添加 calculator 计算器
更换了风格,简洁
一、前言
这是一个综合性的单位换算工具,提供了多种常用计量单位之间的转换功能。不断完善 style 各页面风格统一 , 格式一致。
容量单位换算
- 支持在公制单位(升、毫升、立方厘米)
- 美制容量单位(加仑、夸脱、品脱、杯、液体盎司)
- 厨房计量单位(汤匙、茶匙、米杯)之间相互转换
长度单位换算
- 公制长度单位:毫米、厘米、分米、米
- 美制长度单位:英寸、英尺、码、英里
中国传统单位:厘、分、寸、尺、丈、里- 公制重量单位:克、千克、公吨
- 美制重量单位:格令、打兰、盎司、磅、短吨、长吨
- 介绍:蒲式耳、百威特
温度单位换算
- 支持摄氏度(°C)
- 华氏度(°F)
- 开尔文(K)之间的转换
重量单位换算
公制重量:毫克、公克、公斤、公吨美制重量:格令、打兰、盎司、磅、美吨(短吨)、英吨(长吨)中国传统重量单位:分、钱、两、斤、担
气压单位换算
- 支持多种气压单位:巴(bar)、磅力/平方英寸(psi)、千帕(kPa)、标准大气压(atm)、毫米汞柱(mmHg)
特点:
- 界面简洁,操作简单
- 一次性显示所有转换结果
- 分组显示不同计量体系的单位
- 提供清除功能,方便重新输入
- 中英文单位名称显示
这个工具特别适合:
- 烹饪爱好者(在不同食谱单位间转换)
- 国际单位换算
- 工程日常计算
公制 - 美制 - 大中华 之间的:容量 长度 温度 重量 气压 之间的转换
公制 - 美制 - 大中华 单位间转换 | |
容量 | 升 加仑 汤匙 杯 等 |
长度 | 厘米 英寸 毫 厘 等 |
温度 | 摄氏 华氏 开尔文 |
重量 | 克 磅 大小吨 担 钱 两 等 |
气压 | PSI BAR mmHg 等 |
二、页面展示 Updated on 3Apr.2025
1. 主界面
2. 时间单位转换器
3. 工作时长计算器
4.年龄计算器
5.公制 & 美制单位换算器
6.容量单位换算器
其它部分更改
styles.css
完全理解这个文件为什么会越来越大
app.py
加了路由
新建文件
三、完整代码 Updated on 3Apr.2025
1. 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/agecal')
def age_calculator():
# 渲染位于 templates/converters/age calculator 的模板
return render_template('converters/agecal.html')
@app.route('/converters/workhours')
def work_hours():
return render_template('converters/workhours.html')
@app.route('/coverters/metric_converter')
def metric_converter():
return render_template('converters/metric_converter.html')
@app.route('/coverters/liquid_measures')
def liquid_measures():
return render_template('converters/liquid_measures.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9007, debug=True)
2. index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="单位换算工具和科学计算器">
<title>主页 - 单位换算工具</title>
<!-- Tailwind CDN for calculator styling -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- React and ReactDOM -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<!-- Calculator Styles -->
<style>
/* Root CSS variables for theme management */
:root {
--primary-color: #007BFF;
--background-color: #f4f4f4;
--text-color: #333;
--border-color: #ddd;
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: var(--background-color);
}
.container {
display: flex;
justify-content: space-around;
align-items: flex-start;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.tools-list {
list-style: none;
padding: 0;
margin: 0;
display: block;
width: 100%;
}
.tools-list a {
display: inline-block;
width: 100%;
max-width: 180px;
padding: 10px 15px;
font-size: 1.2em;
color: var(--primary-color);
border: 1px solid var(--primary-color);
border-radius: 5px;
text-align: center;
text-decoration: none;
transition: background-color 0.3s, color 0.3s;
background-color: white;
margin: 0 auto 20px;
}
.tools-list a:hover {
background-color: var(--primary-color);
color: white;
}
.centered {
text-align: center;
width: 100%;
margin: 0 auto;
}
h1 {
color: var(--text-color);
font-size: 2em;
margin: 20px 0;
}
.calculator-container {
margin-left: 100px;
flex: 0 0 auto;
}
/* Calculator specific styles */
.calculator {
background-color: #4a4a4a;
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
width: 300px;
}
.model-name {
color: white;
font-size: 14px;
margin-bottom: 10px;
}
.display {
background-color: #c8c8c8;
border: 1px solid #999;
margin-bottom: 15px;
padding: 10px;
text-align: right;
font-family: "Courier New", monospace;
font-size: 24px;
height: 40px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.buttons {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
}
button {
border: none;
border-radius: 5px;
padding: 12px 0;
font-size: 18px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: background-color 0.1s;
}
button:hover {
filter: brightness(90%);
}
button:active {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
transform: translateY(1px);
}
@media (max-width: 768px) {
.container {
flex-direction: column;
align-items: center;
}
.calculator-container {
margin-left: 0;
margin-top: 30px;
}
}
</style>
</head>
<body>
<div class="body">
<div class="centered">
<h1>单位换算工具</h1>
<p>请选择一个单位换算工具:</p>
</div>
<div class="container">
<!-- 左侧工具列表 -->
<div style="flex: 0 1 auto; min-width: 200px;">
<div class="content centered">
<ul class="tools-list">
<li><a href="/converters/time">时间换算器</a></li>
<li><a href="/converters/workhours">工作小时计算器</a></li>
<li><a href="/converters/agecal">年龄计算器</a></li>
</ul>
</div>
<div class="content centered">
<ul class="tools-list">
<li><a href="/coverters/metric_converter">美制&公制单位转换器</a></li>
<li><a href="/coverters/liquid_measures">容量单位换算器</a></li>
</ul>
</div>
</div>
<!-- 右侧计算器 -->
<div id="calculator-root" class="calculator-container"></div>
</div>
</div>
<!-- Calculator Component Script -->
<script type="text/babel">
const Calculator = () => {
const [display, setDisplay] = React.useState('0');
const [memory, setMemory] = React.useState(0);
const [firstOperand, setFirstOperand] = React.useState(null);
const [operator, setOperator] = React.useState(null);
const [waitingForSecondOperand, setWaitingForSecondOperand] = React.useState(false);
// 处理数字输入
const inputDigit = digit => {
if (waitingForSecondOperand) {
setDisplay(String(digit));
setWaitingForSecondOperand(false);
} else {
setDisplay(display === '0' ? String(digit) : display + digit);
}
};
// 处理小数点
const inputDecimal = () => {
if (!display.includes('.')) {
setDisplay(display + '.');
}
};
// 处理基本运算
const handleOperator = nextOperator => {
const inputValue = parseFloat(display);
if (firstOperand === null) {
setFirstOperand(inputValue);
} else if (operator) {
const result = calculate(firstOperand, inputValue, operator);
setDisplay(String(result));
setFirstOperand(result);
}
setWaitingForSecondOperand(true);
setOperator(nextOperator);
};
// 计算结果
const calculate = (first, second, op) => {
switch(op) {
case '+': return first + second;
case '-': return first - second;
case '×': return first * second;
case '÷': return first / second;
default: return second;
}
};
// 科学函数
const handleScientific = func => {
const num = parseFloat(display);
let result;
switch(func) {
case 'sin':
result = Math.sin(num * Math.PI / 180);
break;
case 'cos':
result = Math.cos(num * Math.PI / 180);
break;
case 'tan':
result = Math.tan(num * Math.PI / 180);
break;
case 'x²':
result = Math.pow(num, 2);
break;
case '√':
result = Math.sqrt(num);
break;
case 'π':
result = Math.PI;
break;
default:
result = num;
}
setDisplay(String(result));
};
// 处理内存操作
const handleMemory = operation => {
const currentValue = parseFloat(display);
switch(operation) {
case 'STO':
setMemory(currentValue);
break;
case 'RCL':
setDisplay(String(memory));
break;
default:
break;
}
};
// 清除操作
const clear = () => {
setDisplay('0');
setFirstOperand(null);
setOperator(null);
setWaitingForSecondOperand(false);
};
// 删除最后一位
const handleDelete = () => {
if (display.length > 1) {
setDisplay(display.slice(0, -1));
} else {
setDisplay('0');
}
};
// 正负号转换
const toggleSign = () => {
setDisplay(String(-parseFloat(display)));
};
return (
<div className="calculator">
<div className="model-name">Dave Model-1</div>
<div className="display">{display}</div>
<div className="buttons">
<button className="bg-green-500 text-white" onClick={() => handleScientific('HYP')}>HYP</button>
<button className="bg-green-500 text-white" onClick={() => handleScientific('sin')}>SIN</button>
<button className="bg-green-500 text-white" onClick={() => handleScientific('cos')}>COS</button>
<button className="bg-green-500 text-white" onClick={() => handleScientific('tan')}>TAN</button>
<button className="bg-gray-200" onClick={() => handleOperator('÷')}>÷</button>
<button className="bg-green-500 text-white" onClick={() => handleScientific('π')}>π</button>
<button className="bg-green-500 text-white" onClick={() => handleScientific('x²')}>x²</button>
<button className="bg-green-500 text-white" onClick={() => handleScientific('√')}>√</button>
<button className="bg-green-500 text-white" onClick={() => handleOperator('y^x')}>y^x</button>
<button className="bg-gray-200" onClick={() => handleOperator('×')}>×</button>
<button className="bg-gray-100" onClick={() => inputDigit(7)}>7</button>
<button className="bg-gray-100" onClick={() => inputDigit(8)}>8</button>
<button className="bg-gray-100" onClick={() => inputDigit(9)}>9</button>
<button className="bg-green-500 text-white" onClick={handleDelete}>DEL</button>
<button className="bg-gray-200" onClick={() => handleOperator('-')}>-</button>
<button className="bg-gray-100" onClick={() => inputDigit(4)}>4</button>
<button className="bg-gray-100" onClick={() => inputDigit(5)}>5</button>
<button className="bg-gray-100" onClick={() => inputDigit(6)}>6</button>
<button className="bg-green-500 text-white" onClick={() => handleMemory('RCL')}>RCL</button>
<button className="bg-gray-200" onClick={() => handleOperator('+')}>+</button>
<button className="bg-gray-100" onClick={() => inputDigit(1)}>1</button>
<button className="bg-gray-100" onClick={() => inputDigit(2)}>2</button>
<button className="bg-gray-100" onClick={() => inputDigit(3)}>3</button>
<button className="bg-green-500 text-white" onClick={() => handleMemory('STO')}>STO</button>
<button className="bg-blue-500 text-white" onClick={() => handleOperator('=')}>=</button>
<button className="bg-gray-100" onClick={() => inputDigit(0)}>0</button>
<button className="bg-gray-100" onClick={inputDecimal}>.</button>
<button className="bg-green-500 text-white" onClick={toggleSign}>±</button>
<button className="bg-green-500 text-white" onClick={clear}>CLR</button>
<button className="bg-green-500 text-white">ON</button>
</div>
</div>
);
};
// Mount the Calculator component
const container = document.getElementById('calculator-root');
const root = ReactDOM.createRoot(container);
root.render(React.createElement(Calculator));
</script>
<!-- Babel for JSX transpilation -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.22.20/babel.min.js"></script>
</body>
</html>
2.1 style.css
/* Calculator Component Styles */
:root {
--calc-bg: #4a4a4a;
--display-bg: #c8c8c8;
--btn-function: #3CB043;
--btn-number: #f8f8f8;
--btn-operation: #f0f0f0;
--btn-equals: #4a90e2;
--text-light: #ffffff;
--text-dark: #000000;
--border-color: #999;
--shadow-color: rgba(0, 0, 0, 0.3);
}
/* Calculator Container */
.calculator {
background-color: var(--calc-bg);
padding: 15px;
border-radius: 10px;
box-shadow: 0 4px 8px var(--shadow-color);
width: 300px;
}
/* Model Name */
.model-name {
color: var(--text-light);
font-size: 14px;
margin-bottom: 10px;
font-family: Arial, sans-serif;
}
/* Calculator Display */
.display {
background-color: var(--display-bg);
border: 1px solid var(--border-color);
margin-bottom: 15px;
padding: 10px;
text-align: right;
font-family: "Courier New", monospace;
font-size: 24px;
height: 40px;
display: flex;
align-items: center;
justify-content: flex-end;
border-radius: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Button Grid Layout */
.buttons {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
}
/* Base Button Styles */
button {
background-color: var(--btn-number);
border: none;
border-radius: 5px;
padding: 12px 0;
font-size: 18px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
transition: all 0.1s ease;
user-select: none;
}
button:hover {
filter: brightness(90%);
}
button:active {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
transform: translateY(1px);
}
/* Function Buttons */
.function-btn {
background-color: var(--btn-function);
color: var(--text-light);
}
/* Operation Buttons */
.operation-btn {
background-color: var(--btn-operation);
}
/* Number Buttons */
.number-btn {
background-color: var(--btn-number);
}
/* Equals Button */
.equals-btn {
background-color: var(--btn-equals);
color: var(--text-light);
}
/* Responsive Design */
@media screen and (max-width: 320px) {
.calculator {
width: 100%;
padding: 10px;
}
.buttons {
gap: 6px;
}
button {
font-size: 16px;
padding: 10px 0;
}
.display {
font-size: 20px;
height: 35px;
}
}
/* Button States for Touch Devices */
@media (hover: none) {
button:hover {
filter: none;
}
}
/* High Contrast Mode */
@media (prefers-contrast: high) {
:root {
--calc-bg: #000000;
--display-bg: #ffffff;
--btn-function: #006400;
--btn-equals: #00008b;
}
}
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
button {
transition: none;
}
}
/* Print Styles */
@media print {
.calculator {
box-shadow: none;
border: 1px solid #000;
}
.display {
border: 1px solid #000;
background-color: #fff;
}
}
2.2 styles.css
/* Root CSS variables for easy theme management */
:root {
--primary-color: #007BFF;
--primary-hover: #0056b3;
--background-color: #f4f4f4;
--text-color: #333;
--border-color: #ddd;
--shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
/* Base styles */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: var(--background-color);
}
/* Core layout */
.body {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.container {
display: flex;
justify-content: center;
align-items: flex-start;
gap: 20px;
margin: 0 auto;
padding: 20px;
}
/* Headings and text */
h1, h2 {
color: var(--text-color);
margin: 10px 0;
text-align: center;
}
.centered {
text-align: center;
width: 100%;
margin: 0 auto;
}
/* Tools list styling */
.tools-list {
list-style: none;
padding: 0;
margin: 0;
width: 180px;
}
.tools-list li {
margin-bottom: 20px;
}
.tools-list a {
display: block;
width: 100%;
padding: 10px 15px;
font-size: 1.2em;
color: var(--primary-color);
border: 1px solid var(--primary-color);
border-radius: 5px;
text-align: center;
text-decoration: none;
transition: background-color 0.3s, color 0.3s;
background-color: white;
box-sizing: border-box;
}
.tools-list a:hover {
background-color: var(--primary-color);
color: white;
}
/* Content sections */
.content {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
text-align: center;
}
.calculator-container {
flex: 0 0 auto;
}
/* Form elements */
input[type="text"],
input[type="number"] {
width: 120px;
padding: 8px;
font-size: 1em;
border: 1px solid var(--border-color);
border-radius: 4px;
}
select {
width: 120px;
padding: 8px;
font-size: 0.9em;
border: 1px solid var(--border-color);
border-radius: 4px;
background-colo