一、效果展示

1.设备信息查询

【定制开发】【M1】W字长文,基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统_flask

2.企业员工信息查询 【定制开发】【M1】W字长文,基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统_sqlite_02

 3.新设备登记

【定制开发】【M1】W字长文,基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统_python_03

 4.新设备入库

【定制开发】【M1】W字长文,基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统_sqlite_04

5.员工借用设备

【定制开发】【M1】W字长文,基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统_sqlite_05

6.员工归还设备 

【定制开发】【M1】W字长文,基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统_flask_06

二、系统功能

功能:

设备管理:入库管理(新设备入库 -> 新设备登记),借用设备,归还设备

信息设置:管理员信息设置

设备信息查询:设备名,生产商,类别,设备编号

员工信息查询:员工卡号,有效期,是否欠费,归还日期

管理员信息个人信息及权限,修改密码

登录登出

角色:

本套管理系统分为两类用户角色:企业员工管理员

企业员工可以查看设备信息和查看借用记录,在登录页顶端导航栏切换功能,不用输入用户名、密码

管理员可使用一切功能,需要使用账号、密码登陆后,进行日常业务操作

演示Demo

设备信息设备名,可填写 “频谱分析仪” ,“三维扫描仪”;

类别,可填写 “分析设备” 等;

员工工卡,可填写:16000001;

三、整体框架


类目



内容



简介



开发语言



Python 3



为什么用Python?

Python 荣获 2020 年度编程语言称号,同时,Python 也是自 TIOBE 榜单发布以来,首款四次获得该奖项的编程语言。Python 在2020年实现了 2.01% 的正增长,紧随其后的是 C++ 实现了 1.99% 的增长率。其他编程语言中,C(+1.66%)、Groovy (+1.23%)、R (+1.10%)分别位居其后。



后端框架



Flask



Flask 是一个微型“microframework”的 Python 开发的 Web 框架,基于WSGI工具箱和​​Jinja2​​ 模板引擎,Flask使用BSD授权。以其自由,灵活,可扩展性强,被广泛使用在各类服务端架构中



前端框架



LayUI



开源模块化前端 UI 框架。由职业前端倾情打造,面向全层次的前后端开发者,易上手开源免费的 Web UI 组件库



数据库



SQLite



SQLite是一款非常轻量级的关系数据库系统,支持多数SQL92标准。SQLite在使用前不需要安装设置,不需要进程来启动、停止或配置,而其他大多数SQL数据库引擎是作为一个单独的服务器进程,被程序使用某种内部进程通信(典型的是TCP/IP),完成发送请求到服务器和接收查询结果的工作,SQLite不采用这种工作方式。使用SQLite时,访问数据库的程序直接从磁盘上的数据库文件读写,没有中间的服务器进程。使用SQLite一般只需要带上一个dll,就可以使用它的全部功能。

SQLite的主要应用场景有作为手机应用的数据库以及小型桌面软件的数据库。


四、关键代码

前端代码

{% extends "base.html" %}
{% block title %}借用设备{% endblock %}

{% block card %}<div class="layui-card-header"><h2>借用设备</h2></div>{% endblock %}
{% block body %}
<form class="layui-form" method="post" id="searchForm">
<!--{{ form.csrf_token }}-->
<div class="layui-form-item">
<div class="layui-inline">
<label style="font-size: medium;width: 150px;" class="layui-form-label">员工卡号:</label>
<div class="layui-input-inline">
{{ form.card(class="layui-input", id="card") }}
</div>
<label style="font-size: medium;width: 80px;" class="layui-form-label">设备名称:</label>
<div class="layui-input-inline">
{{ form.equipment_name(class="layui-input", id="equipment_name") }}
</div>
<div class="layui-input-inline">{{ form.submit(class="layui-btn", id="search") }}</div>
</div>
</div>
</form>
<div id="remove">
<table lay-even id="result" lay-filter="re">
<thead>
<tr>
<th lay-data="{field:'barcode', width:160}">设备条形码</th>
<th lay-data="{field:'equipmentNo', width:180}">设备编号</th>
<th lay-data="{field:'equipment_name', width:240}">设备名</th>
<th lay-data="{field:'manufacturer', width:160}">生产商</th>
<th lay-data="{field:'start_date', width:200}">行业</th>
<th lay-data="{field:'end_date'}">操作</th>
</tr>
</thead>
<tbody>

</tbody>
</table>
</div>
<table id="test" lay-filter="test"></table>

{% endblock %}

{% block script %}
<script>
layui.use(['form','table','jquery'], function(){
var form = layui.form;
var table = layui.table;
var $ = layui.$;

table.init('re', {
height: 390
,limit: 7
,page: true
});
table.on('tool(test)', function(obj){ //注:tool是工具条事件名,test是table原始容器的属性 lay-filter="对应的值"
var data = obj.data; //获得当前行数据
var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
//var tr = obj.tr; //获得当前行 tr 的DOM对象
console.log(obj);
if(layEvent === 'borr'){
layer.confirm('确认借出吗?', function(index){
//obj.del(); //删除对应行(tr)的DOM结构,并更新缓存
//向服务端发送删除指令
table.reload('test', {
url: '{{ url_for('out') }}',
where: {
'barcode': data.barcode,
'card': $('#card').val(),
'equipment_name': $('#equipment_name').val()
}
});
layer.close(index);
});
}
});

$(document).ready(function(){
$('#search').on('click',function () {
var form = new FormData(document.getElementById("searchForm"));
if($('#card').val() === "" || $('#equipment_name').val() === ""){
layui.use('layer', function(){
var layer = layui.layer;

layer.msg('请填写查询内容',{time: 800});
});
}
else{
$.ajax({
url:"{{ url_for('find_staff_equipment') }}",
type:"post",
data:form,
processData:false,
contentType:false,
success:function(data){
if(data.length !== 0){
if(data[0].staff === 0){
layui.use('layer', function(){
var layer = layui.layer;

layer.msg('请输入正确员工卡号!',{time: 1000});
});
}
else if(data[0].staff === 1){
layui.use('layer', function(){
var layer = layui.layer;

layer.msg('该员工卡已欠费!',{time: 1000});
});
}
else if(data[0].staff === 2){
layui.use('layer', function(){
var layer = layui.layer;

layer.msg('该员工卡借用已到期!',{time: 1000});
});
}
else if(data[0].staff === 3){
layui.use('layer', function(){
var layer = layui.layer;

layer.msg('该员工卡已挂失!',{time: 1000});
});
}
else{
$('#remove').remove();
table.render({
elem: '#test'
,data:data
,cols: [[
{field:'barcode', title:'设备条形码', width:160}
,{field:'equipmentNo', title:'设备编号', width:180}
,{field:'equipment_name', title:'设备名', width:240}
,{field:'manufacturer', title:'生产商', width:140}
,{field:'industry', title:'行业', width:200}
,{title:'操作', fixed: 'right', align:'center', toolbar: '#barDemo'}
]]
,page: true
,height: 380
,limit: 7
,response: {
statusCode: 200
}
,parseData: function(data){
return {
"code": 200,
"msg": data.message,
"count": data.length,
"data": data
};
}
});
}
}
else {
layui.use('layer', function(){
var layer = layui.layer;

layer.msg('找不到该设备!',{time: 1000});
});
}
}
});

}
return false;
});
});
});
</script>
<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-sm" lay-event="borr">借出</a>
</script>
{% endblock %}

后端代码

@app.route('/change_password', methods=['GET', 'POST'])
@login_required
def change_password():
form = ChangePasswordForm()
if form.password2.data != form.password.data:
flash(u'两次密码不一致!')
if form.validate_on_submit():
if current_user.verify_password(form.old_password.data):
current_user.password = form.password.data
db.session.add(current_user)
db.session.commit()
flash(u'已成功修改密码!')
return redirect(url_for('index'))
else:
flash(u'原密码输入错误,修改失败!')
return render_template("change-password.html", form=form)


@app.route('/change_info', methods=['GET', 'POST'])
@login_required
def change_info():
form = EditInfoForm()
if form.validate_on_submit():
current_user.admin_name = form.name.data
db.session.add(current_user)
flash(u'已成功修改个人信息!')
return redirect(url_for('user_info', id=current_user.admin_id))
form.name.data = current_user.admin_name
id = current_user.admin_id
right = current_user.right
return render_template('change-info.html', form=form, id=id, right=right)


@app.route('/search_equipment', methods=['GET', 'POST'])
@login_required
def search_equipment(): # 这个函数里不再处理提交按钮,使用Ajax局部刷新
form = SearchEquipmentForm()
return render_template('search-equipment.html', name=session.get('name'), form=form)


@app.route('/equipments', methods=['POST'])
def find_equipment():

def find_name():
return Equipment.query.filter(Equipment.equipment_name.like('%'+request.form.get('content')+'%')).all()

def find_manufacturer():
return Equipment.query.filter(Equipment.manufacturer.contains(request.form.get('content'))).all()

def find_class():
return Equipment.query.filter(Equipment.class_name.contains(request.form.get('content'))).all()

def find_equipmentNo():
return Equipment.query.filter(Equipment.equipmentNo.contains(request.form.get('content'))).all()

methods = {
'equipment_name': find_name,
'manufacturer': find_manufacturer,
'class_name': find_class,
'equipmentNo': find_equipmentNo
}
equipments = methods[request.form.get('method')]()
data = []
for equipment in equipments:
count = Inventory.query.filter_by(equipmentNo=equipment.equipmentNo).count()
available = Inventory.query.filter_by(equipmentNo=equipment.equipmentNo, status=True).count()
item = {'equipmentNo': equipment.equipmentNo, 'equipment_name': equipment.equipment_name, 'industry': equipment.industry, 'manufacturer': equipment.manufacturer,
'class_name': equipment.class_name, 'count': count, 'available': available}
data.append(item)
return jsonify(data)


@app.route('/user/equipment', methods=['GET', 'POST'])
def user_equipment():
form = SearchEquipmentForm()
return render_template('user-equipment.html', form=form)


@app.route('/search_staff', methods=['GET', 'POST'])
@login_required
def search_staff():
form = SearchStaffForm()
return render_template('search-staff.html', name=session.get('name'), form=form)


def timeStamp(timeNum):
if timeNum is None:
return timeNum
else:
timeStamp = float(float(timeNum)/1000)
timeArray = time.localtime(timeStamp)
print(time.strftime("%Y-%m-%d", timeArray))
return time.strftime("%Y-%m-%d", timeArray)


@app.route('/staff', methods=['POST'])
def find_staff():
staff = Staff.query.filter_by(card_id=request.form.get('card')).first()
if staff is None:
return jsonify([])
else:
valid_date = timeStamp(staff.valid_date)
return jsonify([{'name': staff.staff_name, 'gender': staff.sex, 'valid_date': valid_date, 'debt': staff.debt}])

数据库代码

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, SelectField, PasswordField
from wtforms.validators import DataRequired, EqualTo, Length


class Login(FlaskForm):
account = StringField(u'账号', validators=[DataRequired()])
password = PasswordField(u'密码', validators=[DataRequired()])
submit = SubmitField(u'登录')


class ChangePasswordForm(FlaskForm):
old_password = PasswordField(u'原密码', validators=[DataRequired()])
password = PasswordField(u'新密码', validators=[DataRequired(), EqualTo('password2', message=u'两次密码必须一致!')])
password2 = PasswordField(u'确认新密码', validators=[DataRequired()])
submit = SubmitField(u'确认修改')


class EditInfoForm(FlaskForm):
name = StringField(u'用户名', validators=[Length(1, 32)])
submit = SubmitField(u'提交')


class SearchEquipmentForm(FlaskForm):
methods = [('equipment_name', '设备名'), ('manufacturer', '生产商'), ('class_name', '类别'), ('equipmentNo', '设备编号')]
method = SelectField(choices=methods, validators=[DataRequired()], coerce=str)
content = StringField(validators=[DataRequired()])
submit = SubmitField('搜索')

五、启动命令

安装依赖库:pip install -r requirements.txt

启动命令:python main.py runserver -p 8080

进入系统: 在浏览器输入http://127.0.0.1">​  http://127.0.0.1​:8080/  

管理员  账号:000001  密码123456

六、源码下载

​【源码】【M1】基于Python+Flask+SQLAlchemy+LayUI实现的设备借用登记系统(建议收藏).zip-管理软件文档类资源-​

注:可以在此基础上继续开发完善新功能。