Signed-off-by: sairate <sairate@sina.cn>
|
@ -5,8 +5,21 @@
|
|||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="c512d54a-7f5f-4cfb-af24-29d5821a33bf" name="更改" comment="Signed-off-by: sairate <sairate@sina.cn>">
|
||||
<change afterPath="$PROJECT_DIR$/templates/info_person.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/scanf_face.py" beforeDir="false" afterPath="$PROJECT_DIR$/scanf_face.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/app.py" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_1.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_1.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_10.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_10.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_2.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_2.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_3.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_3.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_4.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_4.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_5.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_5.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_6.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_6.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_7.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_7.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_8.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_8.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_9.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_9.jpg" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/face_database.db" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/match_log.txt" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/templates/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/index.html" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
|
@ -17,8 +30,8 @@
|
|||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="HTML File" />
|
||||
<option value="Python Script" />
|
||||
<option value="HTML File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
|
@ -171,9 +184,9 @@
|
|||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python.app" />
|
||||
<item itemvalue="Python.run_programs" />
|
||||
<item itemvalue="JavaScript 调试.index.html" />
|
||||
<item itemvalue="Python.scanf_face" />
|
||||
<item itemvalue="Python.run_programs" />
|
||||
<item itemvalue="Python.match_face" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
|
@ -218,7 +231,13 @@
|
|||
<workItem from="1724575613580" duration="168000" />
|
||||
<workItem from="1724718988706" duration="21000" />
|
||||
<workItem from="1724750178311" duration="717000" />
|
||||
<workItem from="1724805879844" duration="2788000" />
|
||||
<workItem from="1724805879844" duration="2896000" />
|
||||
<workItem from="1724814757252" duration="135000" />
|
||||
<workItem from="1724815878356" duration="1035000" />
|
||||
<workItem from="1724817321005" duration="346000" />
|
||||
<workItem from="1724820717241" duration="895000" />
|
||||
<workItem from="1724821991134" duration="19000" />
|
||||
<workItem from="1724822043361" duration="2284000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="sairate">
|
||||
<option name="closed" value="true" />
|
||||
|
@ -273,10 +292,10 @@
|
|||
<option name="LAST_COMMIT_MESSAGE" value="Signed-off-by: sairate <sairate@sina.cn>" />
|
||||
</component>
|
||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||
<SUITE FILE_PATH="coverage/face$run_programs.coverage" NAME="run_programs 覆盖结果" MODIFIED="1724750462326" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$run_programs.coverage" NAME="run_programs 覆盖结果" MODIFIED="1724824221428" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$sqlite.coverage" NAME="sqlite 覆盖结果" MODIFIED="1724310603865" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$match_face.coverage" NAME="match_face 覆盖结果" MODIFIED="1724314395402" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$app.coverage" NAME="app 覆盖结果" MODIFIED="1724807921894" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$app.coverage" NAME="app 覆盖结果" MODIFIED="1724824238878" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$scanf_face.coverage" NAME="scanf_face 覆盖结果" MODIFIED="1724807152252" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
<SUITE FILE_PATH="coverage/face$add_face.coverage" NAME="add_face 覆盖结果" MODIFIED="1724311005030" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
</component>
|
||||
|
|
82
app.py
|
@ -1,16 +1,19 @@
|
|||
from flask import Flask, render_template
|
||||
from flask import Flask, render_template, request, redirect, url_for
|
||||
from flask_socketio import SocketIO, emit
|
||||
import sqlite3
|
||||
import os
|
||||
import eventlet
|
||||
import face_recognition
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['UPLOAD_FOLDER'] = './static/db_image' # 设置文件上传路径
|
||||
socketio = SocketIO(app, async_mode='eventlet')
|
||||
|
||||
# 从数据库中获取匹配日志记录
|
||||
def get_match_logs(db_name="face_database.db"):
|
||||
conn = sqlite3.connect(db_name)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT name, identity,image_path,match_time FROM match_logs") # 去掉了 image_path
|
||||
c.execute("SELECT name, identity, image_path, match_time FROM match_logs")
|
||||
logs = c.fetchall()
|
||||
conn.close()
|
||||
return logs
|
||||
|
@ -21,6 +24,81 @@ def index():
|
|||
logs = get_match_logs()
|
||||
return render_template('index.html', logs=logs)
|
||||
|
||||
# 人员信息页面,展示人员信息并进行CRUD操作
|
||||
@app.route('/info_person', methods=['GET', 'POST'])
|
||||
def info_person():
|
||||
conn = sqlite3.connect('face_database.db')
|
||||
c = conn.cursor()
|
||||
|
||||
if request.method == 'POST':
|
||||
# 添加新人员
|
||||
if 'add' in request.form:
|
||||
name = request.form['name']
|
||||
identity = request.form['identity']
|
||||
image = request.files['image_path']
|
||||
|
||||
# 保存上传的图片并生成编码
|
||||
if image:
|
||||
image_path = os.path.join(app.config['UPLOAD_FOLDER'], image.filename)
|
||||
image.save(image_path)
|
||||
|
||||
# 使用face_recognition生成面部编码
|
||||
loaded_image = face_recognition.load_image_file(image_path)
|
||||
face_encodings = face_recognition.face_encodings(loaded_image)
|
||||
|
||||
if face_encodings:
|
||||
encoding = ','.join(map(str, face_encodings[0])) # 将编码转换为字符串存储
|
||||
image_path = "db_image/"+image.filename # 仅保存文件名以便后续使用
|
||||
else:
|
||||
return "No face detected in the uploaded image."
|
||||
else:
|
||||
image_path = ""
|
||||
encoding = ""
|
||||
|
||||
c.execute("INSERT INTO faces (name, identity, image_path, encoding) VALUES (?, ?, ?, ?)",
|
||||
(name, identity, image_path, encoding))
|
||||
|
||||
# 更新人员信息
|
||||
elif 'update' in request.form:
|
||||
id = request.form['id']
|
||||
name = request.form['name']
|
||||
identity = request.form['identity']
|
||||
image = request.files.get('image_path')
|
||||
|
||||
if image:
|
||||
image_path = os.path.join(app.config['UPLOAD_FOLDER'], image.filename)
|
||||
image.save(image_path)
|
||||
|
||||
# 使用face_recognition生成新的面部编码
|
||||
loaded_image = face_recognition.load_image_file(image_path)
|
||||
face_encodings = face_recognition.face_encodings(loaded_image)
|
||||
|
||||
if face_encodings:
|
||||
encoding = ','.join(map(str, face_encodings[0])) # 将编码转换为字符串存储
|
||||
image_path = image.filename # 仅保存文件名
|
||||
else:
|
||||
return "No face detected in the uploaded image."
|
||||
else:
|
||||
image_path = request.form['current_image_path'] # 使用当前的图片路径
|
||||
encoding = request.form['encoding'] # 使用现有的编码
|
||||
|
||||
c.execute("UPDATE faces SET name=?, identity=?, image_path=?, encoding=? WHERE id=?",
|
||||
(name, identity, image_path, encoding, id))
|
||||
|
||||
# 删除人员信息
|
||||
elif 'delete' in request.form:
|
||||
id = request.form['id']
|
||||
c.execute("DELETE FROM faces WHERE id=?", (id,))
|
||||
|
||||
conn.commit()
|
||||
|
||||
# 获取所有人员记录
|
||||
c.execute("SELECT * FROM faces")
|
||||
persons = c.fetchall()
|
||||
conn.close()
|
||||
|
||||
return render_template('info_person.html', persons=persons)
|
||||
|
||||
# 处理 WebSocket 连接
|
||||
@socketio.on('connect')
|
||||
def handle_connect():
|
||||
|
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
BIN
face_database.db
|
@ -1 +0,0 @@
|
|||
ÀîËÄ,¾ÓÃñ,db_image\test1.jpg
|
After Width: | Height: | Size: 352 KiB |
|
@ -1,22 +1,45 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Face Match Logs</title>
|
||||
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
|
||||
<title>后台管理系统</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
}
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding-top: 20px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.sidebar a {
|
||||
display: block;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.sidebar a:hover {
|
||||
background-color: #575757;
|
||||
}
|
||||
.content {
|
||||
margin-left: 200px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
table {
|
||||
width: 80%;
|
||||
|
@ -36,36 +59,19 @@
|
|||
background-color: #f5f5f5;
|
||||
}
|
||||
img {
|
||||
max-width: 100px; /* 照片最大宽度 */
|
||||
max-width: 100px;
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// 连接到 Socket.IO 服务器
|
||||
var socket = io.connect('http://' + document.domain + ':' + location.port);
|
||||
|
||||
// 监听 'update' 事件
|
||||
socket.on('update', function(data) {
|
||||
var tableBody = document.getElementById('log-table-body');
|
||||
tableBody.innerHTML = ''; // 清空现有的表格行
|
||||
|
||||
// 遍历日志数据并更新表格
|
||||
data.logs.forEach(function(log) {
|
||||
var row = document.createElement('tr');
|
||||
row.innerHTML = '<td>' + log[0] + '</td>' +
|
||||
'<td>' + log[1] + '</td>' +
|
||||
'<td>' + log[3] + '</td>' +
|
||||
'<td><img src="' + '../static/' + log[2] + '" alt="Photo of ' + log[0] + '"></td>';
|
||||
// log[4] 假设是照片的路径
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<a href="/">进入记录</a>
|
||||
<a href="/info_person">人员信息</a>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h1>进入记录</h1>
|
||||
<table border="0">
|
||||
<thead>
|
||||
|
@ -73,12 +79,32 @@
|
|||
<th>姓名</th>
|
||||
<th>身份</th>
|
||||
<th>进入时间</th>
|
||||
<th>照片</th> <!-- 新增照片列 -->
|
||||
<th>照片</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="log-table-body">
|
||||
<!-- 日志行将在 JavaScript 中插入 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var socket = io.connect('http://' + document.domain + ':' + location.port);
|
||||
socket.on('update', function(data) {
|
||||
var tableBody = document.getElementById('log-table-body');
|
||||
tableBody.innerHTML = '';
|
||||
data.logs.forEach(function(log) {
|
||||
var row = document.createElement('tr');
|
||||
row.innerHTML = '<td>' + log[0] + '</td>' +
|
||||
'<td>' + log[1] + '</td>' +
|
||||
'<td>' + log[3] + '</td>' +
|
||||
'<td><img src="' + '../static/' + log[2] + '" alt="Photo of ' + log[0] + '"></td>';
|
||||
tableBody.appendChild(row);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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: 0;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
background-color: #f0f2f5;
|
||||
}
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding-top: 20px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
.sidebar a {
|
||||
display: block;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.sidebar a:hover, .sidebar a.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
.content {
|
||||
margin-left: 200px;
|
||||
padding: 20px;
|
||||
width: calc(100% - 200px);
|
||||
}
|
||||
h1 {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
margin: 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
margin: 20px auto;
|
||||
border-collapse: collapse;
|
||||
background-color: white;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
th, td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
th {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
tr:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
img {
|
||||
max-width: 100px;
|
||||
height: auto;
|
||||
border-radius: 5px;
|
||||
}
|
||||
form {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.form-inline input[type="text"],
|
||||
.form-inline input[type="file"] {
|
||||
width: auto;
|
||||
padding: 5px;
|
||||
margin-right: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.form-inline button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.form-inline button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
.form-container {
|
||||
max-width: 600px;
|
||||
margin: 40px auto;
|
||||
padding: 20px;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.form-container h2 {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
margin-top: 0;
|
||||
text-align: center;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
.form-container .form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.form-container .form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.form-container .form-group input[type="text"],
|
||||
.form-container .form-group input[type="file"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.form-container button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.form-container button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<a href="/">进入记录</a>
|
||||
<a href="/info_person" class="active">人员信息</a>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h1>人员信息管理</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>姓名</th>
|
||||
<th>身份</th>
|
||||
<th>照片</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for person in persons %}
|
||||
<tr>
|
||||
<td>{{ person[1] }}</td>
|
||||
<td>{{ person[2] }}</td>
|
||||
<td><img src="../static/{{ person[3] }}" alt="Photo of {{ person[1] }}"></td>
|
||||
<td>
|
||||
<form method="POST" enctype="multipart/form-data" class="form-inline">
|
||||
<input type="hidden" name="id" value="{{ person[0] }}">
|
||||
<input type="text" name="name" value="{{ person[1] }}" required>
|
||||
<input type="text" name="identity" value="{{ person[2] }}" required>
|
||||
<input type="hidden" name="current_image_path" value="{{ person[3] }}">
|
||||
<input type="file" name="image_path" onchange="previewImage(event, {{ person[0] }})">
|
||||
<input type="text" name="encoding" value="{{ person[4] }}" required>
|
||||
<button type="submit" name="update">更新</button>
|
||||
</form>
|
||||
<form method="POST" class="form-inline">
|
||||
<input type="hidden" name="id" value="{{ person[0] }}">
|
||||
<button type="submit" name="delete">删除</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="form-container">
|
||||
<h2>添加新人员</h2>
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label for="name">姓名</label>
|
||||
<input type="text" name="name" id="name" placeholder="姓名" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="identity">身份</label>
|
||||
<input type="text" name="identity" id="identity" placeholder="身份" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="image_path">照片</label>
|
||||
<input type="file" name="image_path" id="image_path" onchange="previewNewImage(event)" required>
|
||||
<img id="new-image-preview" src="#" alt="New Image Preview" style="max-width: 100px; height: auto; border-radius: 5px; display: none;">
|
||||
</div>
|
||||
<button type="submit" name="add">添加</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 预览现有记录的图像
|
||||
function previewImage(event, personId) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(){
|
||||
var output = document.getElementById('image-preview-' + personId);
|
||||
output.src = reader.result;
|
||||
};
|
||||
reader.readAsDataURL(event.target.files[0]);
|
||||
}
|
||||
|
||||
// 预览添加新人员时的图像
|
||||
function previewNewImage(event) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(){
|
||||
var output = document.getElementById('new-image-preview');
|
||||
output.src = reader.result;
|
||||
output.style.display = 'block';
|
||||
};
|
||||
reader.readAsDataURL(event.target.files[0]);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|