用前端(HTML+Node.js)实现物品借用登记:完整代码示例

news/2025/9/23 15:19:55/文章来源:https://www.cnblogs.com/Goddragon/p/19107265

在日常工作中,经常需要借用各种办公或实验设备、工具及耗材。为了方便管理借用记录、防止物品丢失,同时提高办公效率,我设计了一个前端小程序——物品借用登记系统。该系统支持记录借用人、物品名称、数量、借用说明和日期,并可实时显示借用状态,同时提供归还和删除操作。整个程序基于 HTML、CSS 和 JavaScript 实现,无需复杂环境配置,即可在内部网页中展示使用效果,非常适合研发团队内部管理和演示。

页面结构与样式

HTML 文档声明与语言设置
使用 HTML5,并设置 lang="zh",保证中文显示正常。

头部信息 ()

字符编码 UTF-8,设置页面标题。

内嵌 CSS 样式:

页面整体居中、最大宽度 1080px、字体为 Arial。

表单和表格设计:背景色、圆角、间距、边框及文字对齐。

表格列宽固定、文字换行处理,日期输入框和按钮样式优化。

页面主体内容

标题
居中显示“研发部物品借用登记表”,突出页面用途。

导航按钮
提供“查看未归还记录”和“查看已归还记录”的快速跳转,便于数据筛选。

借用表单

输入项包括:借用人、物品名称、数量、借用说明、借用日期。

借用日期默认显示当前日期。

提交按钮居中,点击提交触发表单逻辑。

记录展示表格

表头列:借用人、物品、数量、借用说明、借用日期、归还日期、状态、操作。

表格主体动态生成,每条记录可执行操作:

归还:未归还记录可选择归还日期并标记已归还。

删除:需要管理员密码确认后才能删除。

前端 JavaScript 功能

初始化
页面加载时自动将借用日期设置为当前日期。

加载记录 (loadRecords)

向后端请求记录数据。

根据状态显示不同操作控件:归还按钮或只显示归还日期。

数据倒序显示,最新记录在前。

删除记录 (deleteRecord)

弹出密码提示,验证后再确认删除。

删除操作通过 Fetch API 请求后端接口。

归还操作 (returnItem)

选择归还日期,发送请求更新记录状态为“已归还”。

表单提交

验证必填信息完整性。

构建记录对象,初始状态为“未归还”,发送到后端。

提交成功后清空表单并刷新记录列表。

数据与状态管理

记录对象结构

name:借用人

item:物品名称

quantity:数量

remark:借用说明

borrowDate:借用日期

returnDate:归还日期

status:借用状态(未归还/已归还)

前端索引

每条记录会添加 _originalIndex 属性,用于操作对应后端记录。

交互逻辑

所有操作(提交、归还、删除)均通过 Fetch API 与后端通信。

页面实时更新,保证数据一致性与操作安全性。

总结

这个程序实现了借用登记、归还管理和数据展示的全流程功能,界面简洁、操作直观,具有以下特点:

易用性:表单简洁,操作逻辑清晰。

实时性:操作后自动刷新列表,无需手动刷新页面。

安全性:删除记录需要管理员密码确认,避免误操作。

前端实现:完全基于 HTML、CSS 和 JavaScript,无需额外依赖,适合内部网页或博客展示。

总结:该系统可作为研发部门日常物品借用管理的轻量级解决方案,可以部署在Windows系统内,进行局域网管理统计登记。

主页面代码如下:

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8" /><title>物品借用登记</title><style>body { font-family: Arial, sans-serif; padding: 20px; max-width: 1080px; margin: auto; }h2 { text-align: center; margin-bottom: 20px; }form { margin-bottom: 20px; background: #f5f5f5; padding: 15px; border-radius: 8px; }.form-group { display: flex; flex-direction: column; margin-bottom: 12px; }label { margin-bottom: 6px; font-weight: bold; }input, button { padding: 8px; font-size: 14px; }button { margin-top: 10px; cursor: pointer; }table { border-collapse: collapse; width: 100%; table-layout: fixed;}th, td { border: 1px solid #ccc;padding: 8px;text-align: center;white-space: normal;      word-break: break-word;   }th { background-color: #f0f0f0;}th:nth-child(1), td:nth-child(1) { width: 60px; }th:nth-child(2), td:nth-child(2) { width: 200px; }th:nth-child(3), td:nth-child(3) { width: 40px; }        th:nth-child(4), td:nth-child(4) { width: 300px; text-align:left; }    input[type="date"] { width: 65%; }.action-btn { margin: 2px; }</style>
</head>
<body><h2>研发部物品借用登记表</h2><!-- 查看未归还/已归还按钮 --><div style="text-align:center; margin-bottom: 20px;"><button onclick="window.location.href='not-returned.html'">查看未归还记录</button><button onclick="window.location.href='returned.html'">查看已归还记录</button></div><form id="borrowForm"><div class="form-group"><label for="name">借用人</label><input type="text" id="name" required /></div><div class="form-group"><label for="item">物品名称</label><input type="text" id="item" required /></div><div class="form-group"><label for="quantity">数量</label><input type="number" id="quantity" min="1" required /></div><div class="form-group"><label for="remark">借用说明</label><input type="text" id="remark" /></div><div class="form-group"><label for="borrowDate">借用日期</label><input type="date" id="borrowDate" style="display:block;margin:0 auto;width:20%; text-align:center;" required /></div><button type="submit" style="display:block;margin:0 auto">提交</button></form><table id="recordTable"><thead><tr><th>借用人</th><th>物品</th><th>数量</th><th>借用说明</th><th>借用日期</th><th>归还日期</th><th>状态</th><th>操作</th></tr></thead><tbody></tbody></table><script>const form = document.getElementById('borrowForm');const tableBody = document.querySelector('#recordTable tbody');document.getElementById('borrowDate').valueAsDate = new Date();function loadRecords() {fetch('/api/records').then(res => res.json()).then(data => {tableBody.innerHTML = '';// 给每条记录添加原数组索引data.forEach((record, idx) => { record._originalIndex = idx; });// 倒序显示data.slice().reverse().forEach((record, index) => {const row = document.createElement('tr');let returnDateInput = '';let returnButton = '';if (record.status === '已归还') {returnDateInput = record.returnDate || '';} else {returnDateInput = `<input type="date" id="returnDate-${index}" />`;returnButton = `<button class="action-btn" onclick="returnItem(${record._originalIndex}, this)">归还</button>`;}row.innerHTML = `<td>${record.name}</td><td>${record.item}</td><td>${record.quantity}</td><td>${record.remark || ''}</td><td>${record.borrowDate}</td><td>${returnDateInput}</td><td>${record.status || '未归还'}</td><td>${returnButton}<button class="action-btn" onclick="deleteRecord(${record._originalIndex})">删除</button></td>`;tableBody.appendChild(row);});}).catch(err => alert('加载数据失败: ' + err.message));}function deleteRecord(index) {const password = prompt('请输入管理员密码进行删除:');if (password === null) return;const correctPassword = '19980216';if (password !== correctPassword) { alert('密码错误'); return; }if (!confirm('确定删除这条记录吗?')) return;fetch(`/api/records/${index}`, { method: 'DELETE' }).then(() => loadRecords()).catch(() => alert('删除失败'));}function returnItem(index, button) {const dateInput = document.getElementById(`returnDate-${index}`);const returnDate = dateInput.value;if (!returnDate) { alert('请选择归还日期'); return; }button.disabled = true;fetch(`/api/records/${index}/return`, {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ returnDate })}).then(() => loadRecords()).catch(() => { alert('归还失败'); button.disabled = false; });}form.addEventListener('submit', e => {e.preventDefault();const name = document.getElementById('name').value.trim();const item = document.getElementById('item').value.trim();const remark = document.getElementById('remark').value.trim();const quantity = parseInt(document.getElementById('quantity').value);const borrowDate = document.getElementById('borrowDate').value;if (!name || !item || !quantity || !borrowDate) {alert('请填写完整信息');return;}const record = { name, item, quantity, remark, borrowDate, returnDate:'', status:'未归还' };fetch('/api/records', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(record) }).then(() => { form.reset(); document.getElementById('borrowDate').valueAsDate = new Date(); loadRecords(); }).catch(() => alert('提交失败'));});loadRecords();</script>
</body>
</html>

未归还记录页面如下

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>未归还记录</title><style>body { font-family: Arial, sans-serif; padding: 20px; max-width: 1080px; margin: auto; }h2 { text-align: center; margin-bottom: 20px; }table { border-collapse: collapse; width: 100%; table-layout: fixed; background: #fff;}th, td { border: 1px solid #ccc;padding: 8px;text-align: center;white-space: normal;word-break: break-word; }th { background-color: #f0f0f0; }th:nth-child(1), td:nth-child(1) { width: 60px; }th:nth-child(2), td:nth-child(2) { width: 200px; }th:nth-child(3), td:nth-child(3) { width: 40px; }th:nth-child(4), td:nth-child(4) { width: 300px; text-align:left; }th:nth-child(5), td:nth-child(5) { width: 100px; }th:nth-child(6), td:nth-child(6) { width: 100px; }button { padding: 4px 8px; cursor: pointer; }.action-btn { margin: 2px; }.center-btn { display:block; margin:0 auto; }</style>
</head>
<body><h2>未归还记录</h2><div style="text-align:center; margin-bottom: 20px;"><button onclick="window.location.href='index.html'">返回主页面</button></div><table id="recordTable"><thead><tr><th>借用人</th><th>物品</th><th>数量</th><th>借用说明</th><th>借用日期</th><th>归还日期</th><th>状态</th><th>操作</th></tr></thead><tbody></tbody></table><script>const tableBody = document.querySelector('#recordTable tbody');function loadRecords() {fetch('/api/records').then(res => res.json()).then(data => {tableBody.innerHTML = '';const notReturned = data.filter(record => record.status === '未归还');notReturned.forEach((record, index) => {const row = document.createElement('tr');row.innerHTML = `<td>${record.name}</td><td>${record.item}</td><td>${record.quantity}</td><td>${record.remark || ''}</td><td>${record.borrowDate}</td><td><input type="date" id="returnDate-${index}" /></td><td>${record.status}</td><td><button class="action-btn" onclick="returnItem(${index}, '${record.name}', '${record.item}')">归还</button></td>`;tableBody.appendChild(row);});}).catch(err => alert('加载数据失败: ' + err.message));}function returnItem(index, name, item) {const dateInput = document.getElementById(`returnDate-${index}`);const returnDate = dateInput.value;if (!returnDate) { alert('请选择归还日期'); return; }// 获取完整记录索引fetch('/api/records').then(res => res.json()).then(data => {const recordIndex = data.findIndex(r => r.name === name && r.item === item && r.status === '未归还');if (recordIndex === -1) { alert('未找到记录'); return; }fetch(`/api/records/${recordIndex}/return`, {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ returnDate })}).then(res => res.json()).then(() => loadRecords()).catch(() => { alert('归还失败'); });});}loadRecords();</script>
</body>
</html>

已归还页面代码如下:

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8" /><title>已归还记录</title><style>body { font-family: Arial, sans-serif; padding: 20px; max-width: 1080px; margin: auto; }h2 { text-align: center; margin-bottom: 20px; }table { border-collapse: collapse; width: 100%; table-layout: fixed;}th, td { border: 1px solid #ccc;padding: 8px;text-align: center;white-space: normal;word-break: break-word; }th { background-color: #f0f0f0;}th:nth-child(1), td:nth-child(1) {width: 60px;}th:nth-child(2), td:nth-child(2) {width: 200px;}th:nth-child(3), td:nth-child(3) {width: 40px;}		th:nth-child(4), td:nth-child(4) {width: 300px;text-align:left;}	</style>
</head>
<body><h2>已归还记录</h2><div style="text-align:center; margin-bottom: 20px;"><button onclick="window.location.href='index.html'">返回主页面</button></div><table id="recordTable"><thead><tr><th>借用人</th><th>物品</th><th>数量</th><th>借用说明</th><th>借用日期</th><th>归还日期</th><th>状态</th></tr></thead><tbody></tbody></table><script>const tableBody = document.querySelector('#recordTable tbody');function loadRecords() {fetch('/api/records').then(res => res.json()).then(data => {tableBody.innerHTML = '';const returned = data.filter(record => record.status === '已归还');returned.forEach(record => {const row = document.createElement('tr');row.innerHTML = `<td>${record.name}</td><td>${record.item}</td><td>${record.quantity}</td><td>${record.remark || ''}</td><td>${record.borrowDate}</td><td>${record.returnDate || ''}</td><td>${record.status}</td>`;tableBody.appendChild(row);});}).catch(err => alert('加载数据失败: ' + err.message));}loadRecords();</script>
</body>
</html>

Express 框架搭建nodejs服务后端代码

const express = require('express');
const fs = require('fs');
const path = require('path');const app = express();
const PORT = 3000;
const DATA_FILE = path.join(__dirname, 'data.json');app.use(express.json());
app.use(express.static(path.join(__dirname, 'public')));// 读取数据
function readDataFile() {if (!fs.existsSync(DATA_FILE)) return [];try {const data = fs.readFileSync(DATA_FILE, 'utf-8').trim();if (!data) return [];  // 如果文件为空,返回空数组return JSON.parse(data);} catch (err) {console.error('读取文件出错:', err);return [];}
}// 写入数据
function writeDataFile(data) {fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2), 'utf-8');
}// 获取所有记录
app.get('/api/records', (req, res) => {res.json(readDataFile());
});// 添加记录
app.post('/api/records', (req, res) => {const { name, item, quantity, borrowDate, remark } = req.body;if (!name || !item || !borrowDate) {return res.status(400).json({ error: '缺少字段' });}const records = readDataFile();records.push({name,item,quantity: quantity || 1,borrowDate,remark: remark || '',returnDate: '',status: '未归还'});writeDataFile(records);res.json({ status: 'success' });
});// 删除记录
app.delete('/api/records/:index', (req, res) => {const index = parseInt(req.params.index);const records = readDataFile();if (isNaN(index) || index < 0 || index >= records.length) {return res.status(400).json({ error: '索引无效' });}records.splice(index, 1);writeDataFile(records);res.json({ status: 'deleted' });
});// 归还记录
app.post('/api/records/:index/return', (req, res) => {const index = parseInt(req.params.index);const { returnDate } = req.body;const records = readDataFile();if (!returnDate || isNaN(index) || index < 0 || index >= records.length) {return res.status(400).json({ error: '无效请求' });}records[index].returnDate = returnDate;records[index].status = '已归还';writeDataFile(records);res.json({ status: 'updated' });
});app.listen(PORT, () => {console.log(`Server running at http://localhost:${PORT}`);
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/912964.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Google智能体Jules小试牛刀

Google智能体Jules小试牛刀Jules 能做什么Google 的 Jules 是一个编程相关的 AI 助手(coding agent),它可以在背景中异步地处理各种代码任务,让开发者腾出时间专注于更重要/更有创意的工作。 处理各种编码任务 Ju…

免费浏览的网站完全静态化成wordpress

一、Ken Burns特效 当使用OpenCV时,最常使用的是图像,但是我们也可以多个图像创建动画,通过引入时间轴更容易可视化。 Ken Burns特效这是一种以电影制片人肯伯恩斯 (Ken Burns) 命名的平移和缩放技术,Ken Burns 效果不是在屏幕上显示大型静态照片,而是裁剪细节,然后平移图…

泰安网站制作哪家好wordpress 建站教程

日志记录是软件开发中不可或缺的功能&#xff0c;它能帮助开发者在应用程序运行时记录重要信息&#xff0c;便于调试和监控。本文将详细介绍C#中的常用日志记录功能以及常用的日志库&#xff0c;包括日志级别控制、日志输出格式、自定义日志目标、结构化日志和异步日志记录。同…

深圳网站设计公司哪家好境外注册网站

根据现实需要&#xff0c;此系统我们设计出一下功能&#xff0c;主要有以下功能模板。 &#xff08;1&#xff09;新闻发布系统前台&#xff1a;首页、时事新闻、公告资讯、个人中心。 &#xff08;2&#xff09;管理员功能&#xff1a;首页、个人中心、用户管理、新闻分类管理…

wordpress第一个版本学seo可以做网站吗

目录 MySQL数据库提权简介 UDF提权 原理 利用条件 利用准备 利用过程 MOF提权 原理 利用条件 利用过程 自启动提权 反弹shell提权 总结 MySQL数据库提权简介 一般数据库提权思路&#xff1a; 检测数据库的存在&#xff08;探测端口&#xff09;获取到数据库的权限…

网站怎么做首页比较好燕郊seo

docker基本命令是一个开源的应用容器引擎&#xff1b;是一个轻量级容器技术&#xff1b;docker主机(Host)&#xff1a;安装了Docker程序的机器&#xff08;Docker直接安装在操作系统之上&#xff09;&#xff1b;docker客户端(Client)&#xff1a;连接docker主机进行操作&#…

外包做网站一般多少钱wordpress中文标题转换拼音插件

用户管理 一个用户必须有一个主组一个用户可以拥有多个组 但是必须一个主组 其它组是临时组一个组可以拥有多个用户用户的信息放到 /etc/passwd 用户的密码 存入 /etc/shadow 组信息存到 /etc/group添加用户 add useradd shengliang 这时候会在 /etc/passwd 下生成一条记录 she…

珠宝行业网站建设生活馆网站开发背景

目录 1.定时任务实现 2.quartz说明 3.存储方式 4.示例 5.定时任务的重新定制&#xff0c;恢复&#xff0c;暂停及删除 1.定时任务实现 定时任务的实现方式有很多&#xff0c;如下&#xff1a; 1.启动类中添加EnableScheduling&#xff0c;开启定时任务功能&#xff0c;然…

搞笑椅子机房语录

抽象2025.9.23 (已知院长同学很爱唱“我要当主席”,此时正在唱校歌) 47:咋都开始唱校歌了 院长:我都当主席了还不能唱校歌了? 珂乌:还是当主席吧

在AI技术快速实现创意的时代,挖掘渗透测试框架新需求成为关键挑战

该篇文章无摘要a.内容描述核心功能定位:该项目是一个可扩展的后渗透测试和对抗仿真框架,采用服务器/客户端架构设计,主要面向专业渗透测试人员。服务器端采用Golang开发,客户端采用C++ QT框架实现跨平台支持。关键…

基于区域的空间域图像融合MATLAB实现

基于区域的空间域图像融合MATLAB实现,结合多尺度区域分割与特征加权策略一、方法原理区域分割 采用SLIC超像素分割算法将图像划分为均匀区域,每个区域包含约200-300个像素。 区域特征提取颜色特征:HSV空间均值 纹理…

网站seo自己怎么做什么是关键词

前言 对象图和包图依然是对系统的静态的描写叙述。UML九种图加上包图&#xff0c;事实上是十幅图。 包图 1.构成 2.包中的元素 类、接口、用例、构件、其他包等。&#xff08;若包被撤销&#xff0c;当中的元素被撤销&#xff09; 3.包之间的关系 泛化、细化、依赖&#xff08;…

甘肃建设职工教育培训中心网站计算机网络设计是干什么的工作

文章目录 前言一、安装cudn二、安装cudnn三、安装pytorch 前言 确保Windows系统版本高于windows10 21H2或Windows11&#xff0c;然后在Windows中将显卡驱动升级到最新即可&#xff0c;WSL2已支持对显卡的直接调用。 一、安装cudn 进入英伟达官网中的cuda下载地址&#xff1…

怎么建造网站天津网站建设品牌推广

微软2024年1月的更新补丁正常更新会出现0x80070643错误&#xff0c;原因是正常安装系统默认的恢复分区留小了&#xff0c;通过压缩系统盘空间然后在diskgenius扩容恢复分区空间可以解决这个问题&#xff0c;但是笔者在进行上述操作时依旧出现了报错&#xff0c;按照网上的说法可…

intitle:律师网站建设的重要性做网站公司怎么样

为什么80%的码农都做不了架构师&#xff1f;>>> ##Win10除了Edge/IE&#xff0c;其他浏览器打开和载入速度都很慢 解决办法&#xff1a;以管理员身份运行cmd&#xff0c;输入netsh winsock reset重置winsock&#xff0c;然后重启电脑即可 转载于:https://my.oschin…

广州建设网站公司哪个济南兴田德润有活动吗做网站的图片=gif

Ajax-05 xhr&#xff08;level-2&#xff09;新特性 responseType属性和response属性 responseType: 表示预期服务器返回的数据的类型 “” &#xff0c;默认空text&#xff0c;和空一样&#xff0c;表示服务器返回的数据是字符串格式json&#xff0c;表示服务器返回的是js…

网站登录 效果代码产品软文范例500字

如果没有正确的工具来汇总和解析日志数据&#xff0c;则几乎不可能找到并了解您正在寻找的信息。 日志有无穷无尽的用途&#xff0c;因为日志本身是无止境的。 应用程序日志&#xff0c;安全日志&#xff0c;BI日志&#xff0c; 林肯日志 &#xff08;好吧&#xff0c;也许不是…

网站留白做301网站打不开

所有的NLP大模型 都是transformer结构 1.Mask attention 的策略不同 2.训练任务目标不同 国内大模型nb公司&#xff1a;百度、清华智谱 一、主流大模型 粉色&#xff1a;Encoder-only。 绿色&#xff1a;Encoder-Decoder&#xff0c;尽头智谱ChatGLM。 蓝色&#xff1a;…

梳理 | 脑神经科学原理学习资料整理

梳理 | 脑神经科学原理学习资料整理 前言 我想,我似乎一直都在试图探寻着什么,但在过去我甚至都不知道这一点 在近一年不断的在和AI交流的过程中我似乎渐渐地看清了自己的一点轮廓 【就像是最开始的这几篇甚至是在和…