html
复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>房租水电费记录</title>
<script type="text/javascript">
document.addEventListener('plusready', function() {
//console.log("所有plus api都应该在此事件发生后调用,否则会出现plus is undefined。")
});
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #0a1f19;
color: #ffffff;
text-shadow: 1px 1px 1px #000000;
text-align: center;
}
/* 凹背景样式 */
.total-cost b,
.common-span {
color: #ffff00;
position: relative;
border-radius: 3px;
font-size: 30px;
padding: 0 5px;
font-weight: bold;
box-shadow: inset -2px -2px 3px rgba(255, 255, 255, 0.589), inset 2px 2px 3px rgba(0, 0, 0, 0.6);
}
.total-cost b::before,
.common-span::before {
content: "";
background: linear-gradient(white, transparent 3%) 50% 50%/97% 97%,
linear-gradient(rgba(255, 255, 255, 0.5), transparent 50%, transparent 80%, rgba(255, 255, 255, 0.5)) 50% 50%/97% 97%;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: 5px;
transform: scale(0.9);
}
.common-h2 {
background-color: #28a7462e;
border-radius: 0 0 2px 2px;
}
/* 日期行 */
.table-body {
display: flex;
flex-direction: column-reverse;
border: 2px solid #ffc;
border-radius: 3px;
}
.date-month {
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black,
inset 0 2px 2px -2px white, inset 0 0 2px 9px #47434c,
inset 0 0 2px 10px #ff0000;
display: flex;
flex-direction: column-reverse;
padding: 10px;
margin: 3px;
border-radius: 3px;
border: 2px solid #ffaa7f;
}
.details,
.rent-row {
width: 100%;
display: flex;
justify-content: space-around;
background-color: #28a745;
border-radius: 5px 5px 0 0;
border: 5px solid #333333;
}
.date-column {
display: flex;
justify-content: space-around;
align-items: center;
/* margin-top: 12px; */
width: 100%;
margin: 0 auto;
background-color: #144756;
}
/*日期标题 */
.date {
transform: translate(-12%, -236%) scale(0.8);
}
.year {
position: relative;
top: 35px;
left: 6px;
padding: 15px 16px 25px 12px;
border-radius: 10px 10px 0 0;
color: rgb(234, 255, 0);
background-color: #ff0000;
}
.recordCheckbox {
position: relative;
transform: translate(90%, 230%) scale(2);
z-index: 999999;
}
h1 {
position: absolute;
border: 5px solid #333;
width: 135px;
line-height: 115px;
font-size: 60px;
letter-spacing: -3px;
-webkit-text-fill-color: transparent;
border-radius: 20px 10px 10px 10px;
box-shadow: inset 4px 4px 4px rgba(255, 255, 255, 0.6), inset -4px -4px 5px rgba(0, 0, 0, 0.6);
}
.month1 {
clip-path: polygon(0% 0%, 100% 0%, 100% 50%, 0% 50%);
text-shadow: 1px 1px 1px #d1ec04;
-webkit-text-stroke: #fffbfb 1px;
}
.month2 {
clip-path: polygon(0% 50%, 100% 50%, 100% 100%, 0% 100%);
transform: translateY(1px);
z-index: 20;
text-shadow: 1px 1px 1px #ff0303;
-webkit-text-stroke: #ffffff 1px;
}
/*日期标题 结束*/
/* 水表 */
.water-meter {
width: 90px;
height: 90px;
margin: 0 10px;
border-radius: 75px;
background: #e0f7fa;
border: 5px solid #0288d1;
position: relative;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.water-meter h2 {
background: linear-gradient(to top, #0091ea, #00bcd4);
border-radius: 0 0 75px 75px;
}
/* 水表 结束*/
/* 电表 */
.electric-meter {
border: 5px solid #333;
border-radius: 10px;
background: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
}
.electric-meter h2 {
background-color: #28a745;
border-radius: 0 0 2px 2px;
}
/* 电表结束 */
.water-meter p {
animation: backgroundChange2 10s infinite;
margin: 4px;
font-size: 25px;
font-weight: bold;
padding: 0 7px 3px 5px;
}
.electric-meter p {
animation: backgroundChange 10s infinite;
margin: 4px;
font-size: 25px;
font-weight: bold;
padding: 0 7px 3px 5px;
}
@keyframes backgroundChange2 {
0%,
10%,
20%,
30%,
40%,
50%,
60%,
70%,
80%,
90%,
100% {
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black,
inset 0 2px 2px -2px white, inset 0 0 2px 7px #47434c,
inset 0 0 2px 22px #ff0000;
color: #cfd601;
border-radius: 33px 33px 0 0;
}
5%,
15%,
25%,
35%,
45%,
55%,
65%,
75%,
85%,
95% {
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black,
inset 0 2px 2px -2px white, inset 0 0 2px 7px #47434c,
inset 0 0 2px 22px #f6ff00;
color: #ffffff;
border-radius: 30px 30px 0 0;
}
}
@keyframes backgroundChange {
0%,
10%,
20%,
30%,
40%,
50%,
60%,
70%,
80%,
90%,
100% {
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black,
inset 0 2px 2px -2px white, inset 0 0 2px 7px #47434c,
inset 0 0 2px 22px #ff0000;
color: #cfd601;
border-radius: 2px;
}
5%,
15%,
25%,
35%,
45%,
55%,
65%,
75%,
85%,
95% {
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black,
inset 0 2px 2px -2px white, inset 0 0 2px 7px #47434c,
inset 0 0 2px 22px #f6ff00;
color: #ffffff;
border-radius: 3px;
}
}
summary {
color: #f6ff00;
}
summary::marker {
color: red;
/* 设置箭头颜色为红色 */
}
.details table {
width: 100%;
text-align: center;
}
.details td {
border: 2px solid #000000;
background-color: #144756;
}
/* 房租 */
/* 总金额 */
.rent,
.total-amount {
background: #0288d1;
margin: 10px 0;
padding: 0 5px;
box-shadow: inset -2px -2px 3px rgba(255, 255, 255, 0.589), inset 2px 2px 3px rgba(0, 0, 0, 0.6);
}
.total-amount {
background: #f30000;
}
.total-cost {
background-color: #248aa6;
}
/* 删除按钮样式 */
#deleteButton {
background-color: red;
/* 背景颜色 */
color: white;
/* 字体颜色 */
border: none;
/* 无边框 */
padding: 0px 5px;
/* 内边距 */
border-radius: 2px;
/* 圆角 */
cursor: pointer;
/* 鼠标指针样式 */
font-size: 16px;
/* 字体大小 */
margin-left: 10px;
/* 左侧外边距 */
}
#deleteButton:hover {
background-color: darkred;
/* 悬停时的背景颜色 */
}
/* 添加按钮样式 */
#addButton {
background-color: green;
/* 背景颜色 */
color: white;
/* 字体颜色 */
border: none;
/* 无边框 */
padding: 0px 5px;
/* 内边距 */
border-radius: 2px;
/* 圆角 */
cursor: pointer;
/* 鼠标指针样式 */
font-size: 16px;
/* 字体大小 */
}
#addButton:hover {
background-color: darkgreen;
/* 悬停时的背景颜色 */
}
.input-length {
/* 最小宽度 */
min-width: 30px;
}
</style>
</head>
<body>
<h2>房租水电费记账本<button id="deleteButton">选中月上的框删除</button></h2>
<div class="header">
<div id="dataTable" class="table">
<div class="input-section">
<label> <input type="month" id="dateInput"></label>
<label> <input type="text" id="rentInput" class="input-length" oninput="adjustWidth(this)"
placeholder="房租"></label>
<label><input type="text" id="waterInput" class="input-length" oninput="adjustWidth(this)"
placeholder="水表"></label>
<label><input type="text" id="electricInput" class="input-length" oninput="adjustWidth(this)"
placeholder="电表"></label>
<label> <input type="text" id="noteInput" class="input-length" oninput="adjustWidth(this)"
placeholder="备注"></label>
<button id="addButton" style="cursor: pointer;">添加</button>
</div>
<div class="table-body"> </div>
<div class="table-footer">
<div class="footer-cell" colspan="2">到底了,没有更多了!</div>
</div>
</div>
</body>
<script>
let rentRecords = initRentRecords(); // 只初始化一次
let totalWaterUsage = 0; // 总用水量
let totalElectricityUsage = 0; // 总用电量
function initRentRecords() {
const storedRecords = localStorage.getItem('房租记录');
return storedRecords ? JSON.parse(storedRecords) : [
// 默认数据
{
"日期": "2024年7月25日",
"房租": 1000,
"水表": 66,
"电表": 2316,
"备注": "房租500元,押金100元",
"禁止删除": true
},
{
"日期": "2024年8月25日",
"房租": 1500,
"水表": 68,
"电表": 2537,
"备注": "3个月房租,8月25日-11月25日",
"禁止删除": true
},
{
"日期": "2024年9月25日",
"房租": 0,
"水表": 71,
"电表": 2600,
"备注": "9月30日抄表数",
"禁止删除": true
},
];
}
// 计算函数
function calcCosts(curr, prev) {
const waterUsage = prev ? curr.水表 - prev.水表 : 0;
const electricityUsage = prev ? curr.电表 - prev.电表 : 0;
const waterFee = waterUsage > 0 ? waterUsage * 5 : 0; // 水费计算
const electricityFee = electricityUsage > 0 ? electricityUsage * 1 : 0; // 电费计算
const total = curr.房租 + waterFee + electricityFee; // 本月总金额计算
// 更新总用水量和总用电量
totalWaterUsage += waterUsage;
totalElectricityUsage += electricityUsage;
return {
waterUsage,
electricityUsage,
waterFee,
electricityFee,
total,
totalWaterUsage, // 返回总用水量
totalElectricityUsage, // 返回总用电量
waterUsageCalc: `${curr.水表} - ${prev ? prev.水表 : curr.水表} = ${waterUsage} (吨)`,
electricityUsageCalc: `${curr.电表} - ${prev ? prev.电表 : curr.电表} = ${electricityUsage} (度)`,
waterFeeCalc: `${waterUsage} * 5 = ${waterFee}(元)`,
electricityFeeCalc: `${electricityUsage} * 1 = ${electricityFee}(元)`,
totalCalc: `${curr.房租} + ${waterFee} + ${electricityFee} = ${total}(元)`,
};
}
// 渲染数据函数
function renderData() {
let totalRent = 0,
totalWaterFee = 0,
totalElectricityFee = 0;
const contentArea = document.getElementById('dataTable').querySelector('.table-body');
let content = ''; // 用于存储所有内容
rentRecords.forEach((record, index) => {
totalRent += record.房租;
const prevRecord = index > 0 ? rentRecords[index - 1] : null;
const {
waterUsage,
electricityUsage,
waterFee,
electricityFee,
total,
waterUsageCalc,
electricityUsageCalc,
waterFeeCalc,
electricityFeeCalc,
totalCalc
} = calcCosts(record, prevRecord);
totalWaterFee += waterFee;
totalElectricityFee += electricityFee;
const month = String(parseInt(record.日期.substring(5, 7), 10)).padStart(2, '0');
// 拼接每一项数据到 content,添加复选框
content += `
<div class="date-month">
<div class="rent-row">
<div >房租:
<b class="rent">${record.房租}元</b></div>
<div >本月已缴总金额:
<b class="total-amount">${total}元</b></div>
</div>
<div class="date-column">
<div class="date">
<div class="year-month">
<sub class="year">${record.日期.substring(0, 5)}</sub>
<input type="checkbox" class="recordCheckbox" data-index="${index}" />
<h1 class="month1">${month}月</h1>
</div>
<h1 class="month2">${month}月</h1>
</div>
<div class="water-meter">
<p>${record.水表}</p>
<h2>水表</h2>
</div>
<div class="electric-meter">
<p>${record.电表}</p>
<h2>电表</h2>
</div>
</div>
<details class="details">
<summary>
查看详细信息
</summary>
<div>
<p><span>首月押金500元</span><span>房租500元/月</span></p>
<p><span>水:5元/吨</span><span>电:1元/度</span></p>
</div>
<table class="details-table">
<tr >
<td>
<div class="rent common-div-left">
<p>500元/月</p>
<span class="common-span">${record.房租}元</span>
<h2 class="common-h2">房租</h2>
</div>
</td>
<td>
<div class="total-amount common-div-right">
<p>${totalCalc}</p>
<b class="common-span">${total}元</b>
<h2 class="common-h2">应缴金额</h2>
</div>
</td>
</tr>
<tr class="usage-row">
<td>
<div class="common-div-left">
<h2 class="common-h2">用水量</h2>
<p>水${waterUsageCalc}</p>
<span class="common-span">${waterUsage}吨</span>
</div>
</td>
<td>
<div class="common-div-right">
<h2 class="common-h2">用电量</h2>
<p>电${electricityUsageCalc}</p>
<span class="common-span">${electricityUsage}度</span>
</div>
</td>
</tr>
<tr class="fees-row">
<td>
<div class="common-div-left">
<h2 class="common-h2">水费</h2>
<p>${waterFeeCalc}</p>
<span class="common-span">${waterFee}元</span>
</div>
</td>
<td>
<div class="common-div-right">
<h2 class="common-h2">电费</h2>
<p>${electricityFeeCalc}</p>
<span class="common-span">${electricityFee}元</span>
</div>
</td>
</tr>
</tr>
<tr class="remarks-row">
<td colspan="2">
<div><b>备注:</b><span>${record.备注}</span> </div>
</td>
</tr>
</table>
<div class="total-cost">
<h3>${rentRecords[0].日期.substring(0, 5)}${rentRecords[0].日期.substring(5, 7)}到${record.日期.substring(0, 5)}${record.日期.substring(5, 7)}
</br>总缴费用<b>${totalRent + totalWaterFee + totalElectricityFee}元</b></h3>
<sub>总房租 <b>${totalRent}元</b> </sub> <sub>总水电费 <b>${totalWaterFee + totalElectricityFee}元</b> </sub>
</br>
<sub>总用水量 <b>${totalWaterUsage}吨</b> </sub>
<sub>总水费 <b>${totalWaterFee}元</b> </sub>
</br>
<sub>总用电量 <b>${totalElectricityUsage}度</b> </sub>
<sub>总电费 <b>${totalElectricityFee}元</b> </sub>
</div>
</details>
</div>
`;
});
// 设置整个内容区域
contentArea.innerHTML = content;
// 最后添加脚注
const footerArea = document.querySelector('.table-footer');
footerArea.innerHTML = `<div class="footer-cell" colspan="2">到底了,没有更多了!</div>`;
}
function updateLocalStorage() {
// 仅在添加或更新时调用此函数
localStorage.setItem('房租记录', JSON.stringify(rentRecords));
}
// 添加新记录的功能
document.getElementById('addButton').addEventListener('click', function() {
const dateInput = document.getElementById('dateInput').value;
const rentInput = parseFloat(document.getElementById('rentInput').value) || 0;
const waterInput = parseFloat(document.getElementById('waterInput').value) || 0;
const electricInput = parseFloat(document.getElementById('electricInput').value) || 0;
const noteInput = document.getElementById('noteInput').value;
// 检查日期是否有效
if (!dateInput) {
alert("请填写有效的日期。");
return;
}
// 创建新记录对象
const newRecord = {
"日期": new Date(dateInput).toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'numeric',
day: 'numeric'
}),
"房租": rentInput,
"水表": waterInput,
"电表": electricInput,
"备注": noteInput,
"禁止删除": false // 新增加的记录默认为可以删除
};
// 将新记录添加到数组
rentRecords.push(newRecord);
// 更新 localStorage
updateLocalStorage();
// 清空输入框
document.getElementById('dateInput').value = '';
document.getElementById('rentInput').value = '';
document.getElementById('waterInput').value = '';
document.getElementById('electricInput').value = '';
document.getElementById('noteInput').value = '';
// 渲染数据
renderData();
});
// 更新 localStorage 的函数
function updateLocalStorage() {
// 仅在添加或更新时调用此函数
localStorage.setItem('房租记录', JSON.stringify(rentRecords));
}
// 创建新记录对象
const newRecord = {
"日期": new Date(dateInput).toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'numeric',
day: 'numeric'
}),
"房租": rentInput,
"水表": waterInput,
"电表": electricInput,
"备注": noteInput,
"禁止删除": false // 新增加的记录默认为可以删除
};
// 添加删除功能
document.getElementById('deleteButton').addEventListener('click', function() {
const checkedBoxes = document.querySelectorAll('.recordCheckbox:checked');
if (checkedBoxes.length === 0) {
alert('请至少选择一个记录来删除。');
return;
}
const confirmDelete = confirm('您确定要删除选中的记录吗?');
if (!confirmDelete) {
return; // 用户选择了取消,不执行删除
}
checkedBoxes.forEach(checkbox => {
const index = parseInt(checkbox.dataset.index, 10);
const record = rentRecords[index];
// 只删除不带有 '禁止删除': true 的记录
if (!record.禁止删除) {
rentRecords.splice(index, 1); // 从数组中删除记录
} else {
alert(`本地记录 '${record.日期}' 不允许删除。`); // 提示用户该记录不可删除
}
});
// 更新 localStorage 和重新渲染数据
updateLocalStorage();
renderData();
});
/* 调整所有输入框宽度*/
function adjustAllInputWidths() {
document.querySelectorAll('.input-length').forEach(adjustWidth); // 遍历所有类名为 'input-length' 的输入框
}
function adjustWidth(input) {
const span = document.createElement('span');
span.style.visibility = 'hidden';
span.style.whiteSpace = 'pre';
span.style.font = getComputedStyle(input).font;
span.style.padding = getComputedStyle(input).padding; // 添加 padding
span.style.border = getComputedStyle(input).border; // 添加 border
span.style.boxSizing = 'content-box'; // 确保不计算 border 和 padding
span.innerText = input.value || '0';
document.body.appendChild(span);
input.style.width = `${span.offsetWidth}px`;
document.body.removeChild(span);
}
// 页面加载完成后执行
window.onload = () => {
renderData(); // 渲染数据
adjustAllInputWidths(); // 然后调整输入框宽度
};
/* 调整所有输入框宽度 结束*/
</script>
</html>