merge #2

Open
mhl5n4sr8 wants to merge 11 commits from master into zrm_branch

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

@ -0,0 +1,129 @@
# 数据储存在wordle.xlsx中数据字段Date,Contest numberWordNumber of reported
# resultsNumber in hard mode1 try2 tries3 tries4 tries5 tries6 tries7 or more tries (X)
# 其中1 try2 tries3 tries4 tries5 tries6 tries7 or more tries (X)为百分比数
# Date格式为2022/1/7Contest number为每天的序号从202开始每天增加1
# Contest number从202开始每天增加1Number of reported results为每天的报告结果数Number in hard mode为每天的hard mode的报告结果数
# Contest number=202表示2022年1月7日Contest number=203表示2022年1月8日以此类推
# 1针对Number of reported results进行lstm时间序列分析,预测2023年3月1日的Number of reported results
import matplotlib.pyplot as plt
# import numpy as np
import pandas as pd
from pandas import DataFrame
from pandas import concat
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from numpy import concatenate
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from math import sqrt
import tensorflow as tf
tf.random.set_seed(2)
# 导入数据xlsx
qy_data = pd.read_excel('history.xlsx')
# 1.针对Number of reported results进行时间序列分析,结合使用lstm和arima模型预测未来30天的Number of reported results
# 删除Word列
data1 = qy_data.drop(['ProductName'], axis=1)
# 将Date列转换为时间格式
data1['Date'] = pd.to_datetime(data1['Date'])
# 将Date列设置为索引
data1 = data1.set_index('Date')
# 画出Number of reported results的折线图
plt.figure(figsize=(20, 10))
plt.plot(data1['Number of reported sales'])
plt.title('Number of reported sales')
plt.xlabel('Date')
plt.ylabel('Number of reported sales')
plt.show()
# 将dataframe转换为array
values = data1.values
# 将数据归一化
scaler = MinMaxScaler(feature_range=(0, 1))
scaled = scaler.fit_transform(values)
# 将数据转换为监督学习问题
def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
n_vars = 1 if type(data) is list else data.shape[1]
df = DataFrame(data)
cols, names = list(), list()
# 输入序列(t-n, ... t-1)
for i in range(n_in, 0, -1):
cols.append(df.shift(i))
names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
# 预测序列(t, t+1, ... t+n)
for i in range(0, n_out):
cols.append(df.shift(-i))
if i == 0:
names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
else:
names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
# 拼接
agg = concat(cols, axis=1)
agg.columns = names
# 删除空值
if dropnan:
agg.dropna(inplace=True)
return agg
reframed = series_to_supervised(scaled, 1, 1)
# 删除不需要的列
reframed.drop(reframed.columns[[7, 8, 9, 10, 11, 12, 13]], axis=1, inplace=True)# 这是指删除第7,8,9,10,11,12,13列分别是1 try2 tries3 tries4 tries5 tries6 tries7 or more tries (X)
print(reframed.head())
# 将数据分为训练集和测试集
values = reframed.values
n_train_days = 330
train = values[:n_train_days, :]
test = values[n_train_days:, :]
# 将数据分为输入和输出
train_X, train_y = train[:, :-1], train[:, -1]
test_X, test_y = test[:, :-1], test[:, -1]
# 将输入转换为3D格式[样本数,时间步长,特征数]
train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))
test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))
print(train_X.shape, train_y.shape, test_X.shape, test_y.shape)
# 构建模型
model = Sequential()
model.add(LSTM(50, input_shape=(train_X.shape[1], train_X.shape[2])))
model.add(Dropout(0.2))
model.add(Dense(1))
model.compile(loss='mae', optimizer='adam')
# 模型训练
history = model.fit(train_X, train_y, epochs=10, batch_size=72, validation_data=(test_X, test_y), verbose=2, shuffle=False)
# 模型预测
yhat = model.predict(test_X)
test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))
# 反归一化
inv_yhat = concatenate((yhat, test_X[:, 1:]), axis=1)
# inv_yhat = scaler.inverse_transform(inv_yhat)
inv_yhat = inv_yhat[:,0]
test_y = test_y.reshape((len(test_y), 1))
inv_y = concatenate((test_y, test_X[:, 1:]), axis=1)
# inv_y = scaler.inverse_transform(inv_y)
inv_y = inv_y[:,0]
# 将预测得到的数据绘制成折线图
# 将y轴数据转换为整数
inv_y = inv_y*200000
inv_yhat = inv_yhat*200000
plt.figure(figsize=(20, 10))
plt.plot(inv_y, label='real')
plt.plot(inv_yhat, label='predict')
plt.legend()
plt.show()
# 模型评估
rmse = sqrt(mean_squared_error(inv_y, inv_yhat))
mae = mean_absolute_error(inv_y, inv_yhat)
r2 = r2_score(inv_y, inv_yhat)
print('Test RMSE: %.3f' % rmse)
print('Test MAE: %.3f' % mae)
print('Test R2: %.3f' % r2)

@ -0,0 +1,166 @@
import serial
error_codes = {
0x00: "成功",
0x01: "模组拒绝该命令",
0x02: "录入/匹配算法已终止",
0x03: "发送消息错误",
0x04: "相机打开失败",
0x05: "未知错误",
0x06: "无效的参数",
0x07: "内存不足",
0x08: "没有已录入的用户",
0x09: "录入超过最大用户数量",
0x0A: "人脸已录入",
0x0C: "活体检测失败",
0x0D: "录入或解锁超时",
0x0E: "加密芯片授权失败",
0x13: "读文件失败",
0x14: "写文件失败",
0x15: "通信协议未加密",
0x17: "RGB 图像没有 ready",
0xFD: "无效信息 IDkey 未写入",
0xFE: "检测错误",
0xFF: "编码错误"
}
status_codes = {
0x00: "人脸正常",
0x01: "未检测到人脸",
0x02: "人脸太靠近图片上边沿,未能录入",
0x03: "人脸太靠近图片下边沿,未能录入",
0x04: "人脸太靠近图片左边沿,未能录入",
0x05: "人脸太靠近图片右边沿,未能录入",
0x06: "人脸距离太远,未能录入",
0x07: "人脸距离太近,未能录入",
0x08: "眉毛遮挡",
0x09: "眼睛遮挡",
0x0A: "脸部遮挡",
0x0B: "录入人脸方向错误",
0x0C: "在闭眼模式检测到睁眼状态",
0x0D: "闭眼状态",
0x0E: "在闭眼模式检测中无法判定睁闭眼状态"
}
def face_recognition(time):
header = bytes([0xEF, 0xAA, 0x12, 0x00, 0x02])
time_bytes = time.to_bytes(2, byteorder='big')
# checksum = sum(bytes([0x12, 0x00, 0x02, 0x00]) + time_bytes) & 0xFF - 4
command = header + time_bytes
checksum = bytes([0x12, 0x00, 0x02]) + time_bytes
xor_result = 0
for byte in checksum:
xor_result ^= byte
command += bytes([xor_result])
return bytes(command)
def face_register(username, time):
header = bytes([0xEF, 0xAA, 0x26, 0x00, 0x28, 0x00])
username_bytes = username.encode('utf-8')
username_bytes = username_bytes.rjust(32, b'\x00')
time_bytes = time.to_bytes(1, byteorder='big')
direction = bytes([0x01, 0x01, 0x00]) + time_bytes + bytes([0x00, 0x00, 0x00])
command = header + username_bytes + direction
checksum = bytes([0x26, 0x00, 0x28, 0x00]) + username_bytes + direction
xor_result = 0
for byte in checksum:
xor_result ^= byte
command += bytes([xor_result])
return bytes(command)
def process_face_recognition_result(data, errorcode):
if errorcode == 0:
username = data[2:34].decode('utf-8')
return username
elif errorcode in error_codes:
print("error:", error_codes[errorcode])
else:
print("未知错误码:", hex(errorcode))
def process_note_msg(command, errorcode, data):
# 在这里编写处理设备忙的情况的代码
print("note:", status_codes[command])
def process_face_register_result(data, errorcode):
if errorcode == 0:
print("注册成功")
return "Success"
elif errorcode in error_codes:
print("error:", error_codes[errorcode])
else:
print("未知错误码:", hex(errorcode))
def process_reply_msg(command, errorcode, data):
if command == 0x12:
return process_face_recognition_result(data, errorcode)
elif command == 0x26:
process_face_register_result(data, errorcode)
else:
print("未知命令:", command)
def process_command(status, command, errorcode, data):
if status == 0x00:
return process_reply_msg(command, errorcode, data)
elif status == 0x01:
process_note_msg(command, errorcode, data)
def read_serial_data(ser):
while ser.read() == bytes([0xEF]):
if ser.read() == bytes([0xAA]):
status = ser.read(1)[0]
if ser.in_waiting >= 2:
data_length_high = ser.read(1)[0]
data_length_low = ser.read(1)[0]
data_length = data_length_low + (data_length_high << 8) - 2
command = ser.read(1)[0]
errorcode = ser.read(1)[0]
data = ser.read(data_length)
checksum = ser.read(1)[0]
return process_command(status, command, errorcode, data)
def recognition(timeout):
# Call the face recognition function
faceserial = serial.Serial("/dev/ttyUSB0", 115200, timeout=0.5)
print("启动人脸识别")
faceserial.write(face_recognition(timeout))
username = ""
while username == "":
result = read_serial_data(faceserial)
if result:
username = result
faceserial.close()
username = username.rstrip('\u0000')
return username
# # 打开串口连接
# faceserial = serial.Serial("COM21", 115200, timeout=0.5)
# print("启动人脸识别")
# faceserial.write(face_recognition(10))
# # faceserial.write(face_register("username", 15))
#
# while True:
# if read_serial_data(faceserial) == 1:
# break
#
# faceserial.close()
def register(username):
faceserial = serial.Serial("/dev/ttyUSB0", 115200, timeout=0.5)
print("启动人脸识别")
faceserial.write(face_register(username, 15))
flag = 0
while flag is 0:
if read_serial_data(faceserial) == "Success":
flag = 1
break
faceserial.close()
return flag

@ -0,0 +1,21 @@
# import RPi.GPIO as GPIO
# from mfrc522 import SimpleMFRC522
import random
import time
# reader = SimpleMFRC522()
def read():
try:
while True:
id, text = reader.read()
return id, text
finally:
GPIO.cleanup()
def readTest():
time.sleep(2)
random_id = random.randint(1, 1000000000)
random_value = random.randint(1, 4)
return random_id, str(random_value)

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "smartshop_be.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

@ -0,0 +1,8 @@
from django.contrib import admin
# Register your models here.
from .models import User, Product, Order
admin.site.register(User)
admin.site.register(Product)
admin.site.register(Order)

@ -0,0 +1,6 @@
from django.apps import AppConfig
class MyappConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'

@ -0,0 +1,33 @@
from django.db import models
class User(models.Model):
username = models.CharField(max_length=255)
password = models.CharField(max_length=255)
balance = models.IntegerField()
is_vip = models.BooleanField()
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
stock = models.IntegerField()
class Order(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
is_paid = models.BooleanField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
products = models.ManyToManyField(Product, through='OrderItem')
@property
def total_price(self):
order_items = self.orderitem_set.all()
total = sum(item.product.price * item.quantity for item in order_items)
return total
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()

@ -0,0 +1,2 @@
# Create your tests here.

@ -0,0 +1,130 @@
# import time
import time
from turtle import delay
from django.http import JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from hardware import face, rfid
product_list = []
productID_list = []
# Create your views here.
def index(request):
return render(request, "back/base.html")
def user_management(request):
return render(request, "back/user_management.html")
def product_management(request):
return render(request, "back/product_management.html")
def order_management(request):
return render(request, "back/order_management.html")
def history_analyze(request):
return render(request, "back/history_analyze.html")
def add_user(request):
if request.method == 'POST':
# 处理添加用户的逻辑
# 从请求中获取表单数据
username = request.POST.get('username')
balance = request.POST.get('balance')
vip = request.POST.get('vip') == 'on' # 处理复选框的值
# 执行添加用户的操作,例如保存到数据库
# 返回JSON响应表示用户已成功添加
return JsonResponse({'status': 'success'})
# 如果不是POST请求直接渲染页面
return render(request, 'front/html/user_management.html')
def refresh_users(request):
# 处理刷新用户列表的逻辑
# 查询数据库或执行其他操作以获取最新的用户列表
# 假设你有一个名为users的列表其中包含用户信息
users = [
{'username': 'User 1', 'balance': 100, 'vip': True},
{'username': 'User 2', 'balance': 200, 'vip': False},
{'username': 'User 3', 'balance': 150, 'vip': True},
]
# 返回JSON响应包含最新的用户列表
return JsonResponse({'users': users})
def login(request):
return render(request, "front/html/logIn.html")
def sign(request):
return render(request, "front/html/signUp.html")
def cart(request):
return render(request, "front/html/shoppingCart.html")
def facerecognition(request):
#username = face.recognition(30)
username = 'Dustin'
#延时三秒
time.sleep(3)
return JsonResponse({'username': username})
@csrf_exempt
def faceregister(request):
# POST请求有username参数
if request.method == 'POST':
username = request.POST.get('username')
face.register(username)
return JsonResponse({'status': 'success'})
def getProd(request):
prodID = request.GET.get('prodID')
if prodID == '1':
return JsonResponse({'prodID': '1', 'prodName': '旺仔小馒头', 'prodPrice': '2.33', 'intro': '好吃,爱吃!'})
elif prodID == '2':
return JsonResponse({'prodID': '2', 'prodName': '旺仔牛奶', 'prodPrice': '4.66', 'intro': '三年六班李子明推荐'})
elif prodID == '3':
return JsonResponse({'prodID': '3', 'prodName': '牛奶糖', 'prodPrice': '3.80', 'intro': '奶香浓郁,回味无穷'})
elif prodID == '4':
return JsonResponse(
{'prodID': '4', 'prodName': '卫龙魔芋爽', 'prodPrice': '0.50', 'intro': '爽滑轻弹,好吃不贵'})
else:
return JsonResponse({'prodID': '0', 'prodName': '商品不存在', 'prodPrice': '0.00', 'intro': '商品不存在'})
#import multiprocessing
def updaterfid(request):
print("try to read")
newProdID, newProdText = rfid.readTest()
print("read success")
print("newProdID:", newProdID)
print("newProdText:", newProdText)
if newProdID not in productID_list:
productID_list.append(str(newProdID))
product_list.append(str(newProdText).rstrip())
print("add success")
# 在超时时间内完成了逻辑处理,直接返回响应
return JsonResponse({'product_list': product_list})
def cleanrfid(request):
productID_list.clear()
product_list.clear()
return JsonResponse({'Status': 'success'})

@ -0,0 +1,16 @@
"""
ASGI config for smartshop_be project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "smartshop_be.settings")
application = get_asgi_application()

@ -0,0 +1,125 @@
"""
Django settings for smartshop_be project.
Generated by 'django-admin startproject' using Django 4.2.5.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
import os.path
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-$8)6@6t4p%(4-=f!q3mn$_!r9wl-s-h+!f+^xp=$&plwo3p670"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = [
"0.0.0.0",
"127.0.0.1",
]
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"myapp.apps.MyappConfig",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "smartshop_be.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / 'templates']
,
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "smartshop_be.wsgi.application"
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
]
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.2/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'templates/front'),
)
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

@ -0,0 +1,41 @@
"""
URL configuration for smartshop_be project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from myapp import views
app_name = "admin"
urlpatterns = [
path("admin/", admin.site.urls),
path("back/", views.index, name="index"),
path("user_management/", views.user_management, name="user_management"),
path("product_management/", views.product_management, name="product_management"),
path("order_management/", views.order_management, name="order_management"),
path("history_analyze/", views.history_analyze, name="history_analyze"),
path('add_user/', views.add_user, name='add_user'),
path('refresh_users/', views.refresh_users, name='refresh_users'),
path('login/', views.login, name='login'),
path('sign/', views.sign, name='sign'),
path('cart/', views.cart, name='cart'),
path('rec/', views.facerecognition, name='rec'),
path('reg/', views.faceregister, name='reg'),
path('getProd/', views.getProd, name='getProd'),
path('updaterfid/', views.updaterfid, name='updaterfid'),
path('cleanrfid/', views.cleanrfid, name='cleanrfid'),
]

@ -0,0 +1,16 @@
"""
WSGI config for smartshop_be project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "smartshop_be.settings")
application = get_wsgi_application()

@ -0,0 +1,92 @@
<!-- base.html -->
<!DOCTYPE html>
<html lang="en">
<style>
/* styles.css */
/* 设置整体样式 */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
/* 设置标题栏样式 */
header {
background-color: #333;
color: #fff;
padding: 20px;
}
h1 {
margin: 0;
}
/* 设置导航栏样式 */
nav ul {
list-style-type: none;
margin: 0;
padding: 0;
background-color: #f1f1f1;
}
nav li {
display: inline-block;
margin-right: 10px;
}
nav a {
display: block;
padding: 10px;
text-decoration: none;
color: #333;
}
nav a:hover {
background-color: #333;
color: #fff;
}
/* 设置主要内容区域样式 */
main {
padding: 20px;
}
/* 示例页面样式 */
.user-management-page {
background-color: #f9f9f9;
padding: 10px;
}
.product-management-page {
background-color: #f9f9f9;
padding: 10px;
}
.order-management-page {
background-color: #f9f9f9;
padding: 10px;
}
</style>
<head>
<meta charset="UTF-8">
<title>无人超市后台管理系统</title>
</head>
<body>
<header>
<h1>无人超市后台管理系统</h1>
</header>
<nav>
<ul>
<li><a href="{% url 'user_management' %}">用户管理</a></li>
<li><a href="{% url 'product_management' %}">商品管理</a></li>
<li><a href="{% url 'order_management' %}">订单管理</a></li>
<li><a href="{% url 'history_analyze' %}">销售历史情况分析</a></li>
</ul>
</nav>
<main>
{% block content %}
{% endblock %}
</main>
</body>
</html>

@ -0,0 +1,328 @@
<!-- product_management.html -->
{% extends 'back/base.html' %}
{% block content %}
<style>
/* 页面样式 */
body {
font-family: Arial, sans-serif;
}
h2 {
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
#add-product-btn,
#refresh-button {
padding: 10px 20px;
margin-bottom: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal {
display: none;
position: fixed;
z-index: 999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 400px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
.close {
color: #888;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#product-form label {
display: block;
margin-top: 10px;
}
#product-form input[type="text"],
#product-form input[type="number"],
#product-form input[type="checkbox"] {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.modal-buttons {
margin-top: 20px;
text-align: right;
}
.modal-buttons button {
margin-left: 10px;
}
/* 其他样式 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 999;
}
.loading{
position: fixed;
top: 60%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999;
}
</style>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<h2>商品管理</h2>
<button id="add-product-btn" style="display: none">分析商品</button>
<button id="refresh-button">刷新</button>
<table id="product-table">
<thead>
<tr>
<th>ID</th>
<th>商品名</th>
<th>单价(单位:分)</th>
<th>剩余库存</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{# {% for user_profile in user_profiles %}#}
{# <tr>#}
{# <td>{{ user_profile.user.id }}</td>#}
{# <td>{{ user_profile.user.username }}</td>#}
{# <td>{{ user_profile.balance }}</td>#}
{# <td>{% if user_profile.is_vip %}是{% else %}否{% endif %}</td>#}
{# <td>{{ user_profile.face_id }}</td>#}
{# <td>#}
{# <button class="edit-button" data-user-id="{{ user_profile.user.id }}">修改</button>#}
{# <button class="delete-button" data-user-id="{{ user_profile.user.id }}">删除</button>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
<tr>
<td>1</td>
<td>可乐</td>
<td>300</td>
<td>20</td>
<td>
<button class="edit-button" data-product-id="1">分析</button>
<button class="delete-button" data-product-id="1">删除</button>
</td>
</tr>
<tr>
<td>2</td>
<td>雪碧</td>
<td>300</td>
<td>20</td>
<td>
<button class="edit-button" data-product-id="2">分析</button>
<button class="delete-button" data-product-id="2">删除</button>
</tr>
</tbody>
</table>
<!-- 弹窗 -->
<div id="product-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3 id="modal-title">分析商品</h3>
<form id="product-form">
<!-- 商品信息表单字段 -->
<input type="hidden" id="product-id" name="product-id">
<label for="productname">商品名:</label>
<label for="productname">可乐</label>
<label for="price">单价(单位:分)</label>
<label for="price">3.00</label>
<label for="stock">库存:</label>
<label for="stock">20</label>
<br>
<label for="time">分析时间:</label>
<select name="time">
<option value="1">一个月</option>
<option value="2">一年</option>
</select>
<!-- 保存和取消按钮 -->
<div class="modal-buttons">
<button type="submit" class="save-button">分析</button>
<button type="button" class="cancel-button">取消</button>
</div>
</form>
</div>
</div>
<!-- 预测结果图片 -->
<div class="modal-img" style="display: none">
<img src="https://ooo.0x0.ooo/2023/11/14/OeRNLj.png" alt="预测结果" width="100%">
<img src="https://ooo.0x0.ooo/2023/11/14/OeRAFU.png" alt="预测结果" width="100%">
</div>
<div class="loading" style="display: none">
<img src="https://www.sucaijishi.com/uploadfile/2018/0919/20180919030732302.gif" alt="加载中..." >
</div>
<script>
// 弹窗显示和隐藏
var modal = document.getElementById("product-modal");
var btn = document.getElementById("add-product-btn");
var span = document.getElementsByClassName("close")[0];
var form = document.getElementById("product-form");
var modalTitle = document.getElementById("modal-title");
var productIdField = document.getElementById("product-id");
btn.onclick = function () {
modalTitle.textContent = "添加商品";
form.reset();
modal.style.display = "block";
}
span.onclick = function () {
modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// 刷新按钮点击事件
var refreshButton = document.getElementById("refresh-button");
refreshButton.addEventListener("click", function () {
// 在这里可以执行获取最新内容的操作
// 例如:通过 AJAX 请求获取最新的商品列表数据并刷新表格内容
});
// 页面加载完成后执行的操作
window.addEventListener("load", function () {
// 在这里可以执行页面加载完成后的操作
// 例如:初始化页面、获取初始数据等
});
// 修改按钮点击事件
var editButtons = document.querySelectorAll(".edit-button");
editButtons.forEach(function (button) {
button.addEventListener("click", function () {
var productId = button.getAttribute("data-product-id");
modalTitle.textContent = "分析商品";
productIdField.value = productId;
// 根据商品ID获取其他商品信息并填充到表单中
// 可以通过 AJAX 请求获取商品信息
// 然后将商品信息填充到表单字段中
modal.style.display = "block";
});
});
// 删除按钮点击事件
var deleteButtons = document.querySelectorAll(".delete-button");
deleteButtons.forEach(function (button) {
button.addEventListener("click", function () {
var productId = button.getAttribute("data-product-id");
// 根据商品ID执行删除商品操作
// 可以通过 AJAX 请求将商品ID发送到后端进行删除
// 然后可以根据返回的结果刷新商品列表或进行其他操作
});
});
// 添加/编辑商品表单提交
form.addEventListener("submit", function (event) {
event.preventDefault();
var productId = productIdField.value;
// 在这里可以通过 JavaScript 获取表单字段的值,进行保存等操作
// 例如:通过 AJAX 请求将表单数据发送到后端进行保存
// 然后可以根据返回的结果刷新商品列表或进行其他操作
modal.style.display = "none";
});
// 取消按钮点击事件
var cancelButton = document.querySelector(".cancel-button");
cancelButton.addEventListener("click", function () {
modal.style.display = "none";
});
$(document).ready(function() {
// 添加商品按钮点击事件
$('#add-product-btn').click(function() {
// 显示弹窗
$('#product-modal').show();
$('.overlay').show();
$('#modal-title').text('分析商品');
});
// 关闭弹窗按钮点击事件
$('.close').click(function() {
// 隐藏弹窗
$('#product-modal').hide();
$('.overlay').hide();
});
// 取消按钮点击事件
$('.cancel-button').click(function() {
// 隐藏弹窗
$('#product-modal').hide();
$('.overlay').hide();
});
//保存按钮点击事件
$('.save-button').click(function() {
// 隐藏弹窗
//控制台输出
console.log("分析商品");
$('.loading').show();
$('#product-modal').hide();
$('.overlay').hide();
//延时三秒
setTimeout(function() {
//显示图片
$('.loading').hide();
$('.modal-img').show();
}, 5000);
});
});
</script>
{% endblock %}

@ -0,0 +1,372 @@
<!-- order_management.html -->
{% extends 'back/base.html' %}
{% block content %}
<style>
/* 页面样式 */
body {
font-family: Arial, sans-serif;
}
h2 {
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
#add-order-btn,
#refresh-button {
padding: 10px 20px;
margin-bottom: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal {
display: none;
position: fixed;
z-index: 999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 400px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
.close {
color: #888;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#order-form label {
display: block;
margin-top: 10px;
}
#order-form input[type="text"],
#order-form input[type="number"],
#order-form input[type="checkbox"] {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.modal-buttons {
margin-top: 20px;
text-align: right;
}
.modal-buttons button {
margin-left: 10px;
}
/* 其他样式 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 999;
}
</style>
<h2>订单管理</h2>
<button id="add-order-btn">添加订单</button>
<button id="refresh-button">刷新</button>
<table id="order-table">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>金额</th>
<th>是否已支付</th>
<th>用户ID</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{# {% for order_profile in order_profiles %}#}
{# <tr>#}
{# <td>{{ order_profile.order.id }}</td>#}
{# <td>{{ order_profile.order.ordername }}</td>#}
{# <td>{{ order_profile.balance }}</td>#}
{# <td>{% if order_profile.is_vip %}是{% else %}否{% endif %}</td>#}
{# <td>{{ order_profile.face_id }}</td>#}
{# <td>#}
{# <button class="edit-button" data-order-id="{{ order_profile.order.id }}">修改</button>#}
{# <button class="delete-button" data-order-id="{{ order_profile.order.id }}">删除</button>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
<tr>
<td>1</td>
<td>张三</td>
<td>100</td>
<td></td>
<td>1</td>
<td>
<button class="edit-button" data-order-id="1">修改</button>
<button class="delete-button" data-order-id="1">删除</button>
</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>200</td>
<td></td>
<td>2</td>
<td>
<button class="edit-button" data-order-id="2">修改</button>
<button class="delete-button" data-order-id="2">删除</button>
</td>
</tr>
</tbody>
</table>
<!-- 弹窗 -->
<div id="order-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3 id="modal-title">添加订单</h3>
<form id="order-form">
<!-- 订单信息表单字段 -->
<input type="hidden" id="order-id" name="order-id">
<label for="ordername">用户名:</label>
<input type="text" id="ordername" name="ordername" required>
<label for="balance">金额:</label>
<input type="number" id="balance" name="balance" required>
<label for="vip">是否已支付:</label>
<input type="checkbox" id="vip" name="vip">
<!-- 保存和取消按钮 -->
<div class="modal-buttons">
<button type="submit" class="save-button">保存</button>
<button type="button" class="cancel-button">取消</button>
</div>
</form>
</div>
</div>
<script>
// 弹窗显示和隐藏
var modal = document.getElementById("order-modal");
var btn = document.getElementById("add-order-btn");
var span = document.getElementsByClassName("close")[0];
var form = document.getElementById("order-form");
var modalTitle = document.getElementById("modal-title");
var orderIdField = document.getElementById("order-id");
btn.onclick = function () {
modalTitle.textContent = "添加订单";
form.reset();
modal.style.display = "block";
}
span.onclick = function () {
modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// 刷新按钮点击事件
var refreshButton = document.getElementById("refresh-button");
refreshButton.addEventListener("click", function () {
// 在这里可以执行获取最新内容的操作
// 例如:通过 AJAX 请求获取最新的订单列表数据并刷新表格内容
});
// 页面加载完成后执行的操作
window.addEventListener("load", function () {
// 在这里可以执行页面加载完成后的操作
// 例如:初始化页面、获取初始数据等
});
// 修改按钮点击事件
var editButtons = document.querySelectorAll(".edit-button");
editButtons.forEach(function (button) {
button.addEventListener("click", function () {
var orderId = button.getAttribute("data-order-id");
modalTitle.textContent = "修改订单";
orderIdField.value = orderId;
// 根据订单ID获取其他订单信息并填充到表单中
// 可以通过 AJAX 请求获取订单信息
// 然后将订单信息填充到表单字段中
modal.style.display = "block";
});
});
// 删除按钮点击事件
var deleteButtons = document.querySelectorAll(".delete-button");
deleteButtons.forEach(function (button) {
button.addEventListener("click", function () {
var orderId = button.getAttribute("data-order-id");
// 根据订单ID执行删除订单操作
// 可以通过 AJAX 请求将订单ID发送到后端进行删除
// 然后可以根据返回的结果刷新订单列表或进行其他操作
});
});
// 添加/编辑订单表单提交
form.addEventListener("submit", function (event) {
event.preventDefault();
var orderId = orderIdField.value;
// 在这里可以通过 JavaScript 获取表单字段的值,进行保存等操作
// 例如:通过 AJAX 请求将表单数据发送到后端进行保存
// 然后可以根据返回的结果刷新订单列表或进行其他操作
modal.style.display = "none";
});
// 取消按钮点击事件
var cancelButton = document.querySelector(".cancel-button");
cancelButton.addEventListener("click", function () {
modal.style.display = "none";
});
$(document).ready(function() {
// 添加订单按钮点击事件
$('#add-order-btn').click(function() {
// 显示弹窗
$('#order-modal').show();
$('.overlay').show();
$('#modal-title').text('添加订单');
});
// 关闭弹窗按钮点击事件
$('.close').click(function() {
// 隐藏弹窗
$('#order-modal').hide();
$('.overlay').hide();
});
// 取消按钮点击事件
$('.cancel-button').click(function() {
// 隐藏弹窗
$('#order-modal').hide();
$('.overlay').hide();
});
// 保存按钮点击事件
$('.save-button').click(function(e) {
e.preventDefault();
// 获取表单数据
var ordername = $('#ordername').val();
var balance = $('#balance').val();
var vip = $('#vip').is(':checked');
// 发送POST请求到添加订单的URL
$.ajax({
url: '/add_order/',
type: 'POST',
data: {
'ordername': ordername,
'balance': balance,
'vip': vip
},
success: function(response) {
// 添加订单成功后的处理逻辑
// 隐藏弹窗
$('#order-modal').hide();
$('.overlay').hide();
// 清空表单数据
$('#ordername').val('');
$('#balance').val('');
$('#vip').prop('checked', false);
// 刷新订单列表
refreshOrderTable();
},
error: function(xhr, errmsg, err) {
// 处理错误情况
console.log(errmsg);
}
});
});
// 刷新按钮点击事件
$('#refresh-button').click(function() {
// 刷新订单列表
refreshOrderTable();
});
// 刷新订单列表函数
function refreshOrderTable() {
// 发送GET请求到刷新订单列表的URL
$.ajax({
url: '/refresh_orders/',
type: 'GET',
success: function(response) {
// 更新订单列表
var orders = response.orders;
var tableBody = $('#order-table tbody');
tableBody.empty();
for (var i = 0; i < orders.length; i++) {
var order = orders[i];
var row = '<tr>' +
'<td>' + order.ordername + '</td>' +
'<td>' + order.balance + '</td>' +
'<td>' + (order.vip ? '是' : '否') + '</td>' +
'</tr>';
tableBody.append(row);
}
},
error: function(xhr, errmsg, err) {
// 处理错误情况
console.log(errmsg);
}
});
}
// 页面加载时刷新订单列表
refreshOrderTable();
});
</script>
{% endblock %}

@ -0,0 +1,368 @@
<!-- product_management.html -->
{% extends 'back/base.html' %}
{% block content %}
<style>
/* 页面样式 */
body {
font-family: Arial, sans-serif;
}
h2 {
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
#add-product-btn,
#refresh-button {
padding: 10px 20px;
margin-bottom: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal {
display: none;
position: fixed;
z-index: 999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 400px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
.close {
color: #888;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#product-form label {
display: block;
margin-top: 10px;
}
#product-form input[type="text"],
#product-form input[type="number"],
#product-form input[type="checkbox"] {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.modal-buttons {
margin-top: 20px;
text-align: right;
}
.modal-buttons button {
margin-left: 10px;
}
/* 其他样式 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 999;
}
</style>
<h2>商品管理</h2>
<button id="add-product-btn">新增库存</button>
<button id="refresh-button">刷新</button>
<table id="product-table">
<thead>
<tr>
<th>ID</th>
<th>商品名</th>
<th>单价(单位:分)</th>
<th>剩余库存</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{# {% for user_profile in user_profiles %}#}
{# <tr>#}
{# <td>{{ user_profile.user.id }}</td>#}
{# <td>{{ user_profile.user.username }}</td>#}
{# <td>{{ user_profile.balance }}</td>#}
{# <td>{% if user_profile.is_vip %}是{% else %}否{% endif %}</td>#}
{# <td>{{ user_profile.face_id }}</td>#}
{# <td>#}
{# <button class="edit-button" data-user-id="{{ user_profile.user.id }}">修改</button>#}
{# <button class="delete-button" data-user-id="{{ user_profile.user.id }}">删除</button>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
<tr>
<td>1</td>
<td>可乐</td>
<td>300</td>
<td>20</td>
<td>
<button class="edit-button" data-product-id="1">修改</button>
<button class="delete-button" data-product-id="1">删除</button>
</td>
</tr>
<tr>
<td>2</td>
<td>雪碧</td>
<td>300</td>
<td>20</td>
<td>
<button class="edit-button" data-product-id="2">修改</button>
<button class="delete-button" data-product-id="2">删除</button>
</tr>
</tbody>
</table>
<!-- 弹窗 -->
<div id="product-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3 id="modal-title">添加商品</h3>
<form id="product-form">
<!-- 商品信息表单字段 -->
<input type="hidden" id="product-id" name="product-id">
<label for="productname">商品名:</label>
<input type="text" id="productname" name="productname" required>
<label for="price">单价(单位:分)</label>
<input type="number" id="price" name="price" required>
<label for="stock">库存:</label>
<input type="number" id="stock" name="stock" required>
<!-- 保存和取消按钮 -->
<div class="modal-buttons">
<button type="submit" class="save-button">保存</button>
<button type="button" class="cancel-button">取消</button>
</div>
</form>
</div>
</div>
<script>
// 弹窗显示和隐藏
var modal = document.getElementById("product-modal");
var btn = document.getElementById("add-product-btn");
var span = document.getElementsByClassName("close")[0];
var form = document.getElementById("product-form");
var modalTitle = document.getElementById("modal-title");
var productIdField = document.getElementById("product-id");
btn.onclick = function () {
modalTitle.textContent = "添加商品";
form.reset();
modal.style.display = "block";
}
span.onclick = function () {
modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// 刷新按钮点击事件
var refreshButton = document.getElementById("refresh-button");
refreshButton.addEventListener("click", function () {
// 在这里可以执行获取最新内容的操作
// 例如:通过 AJAX 请求获取最新的商品列表数据并刷新表格内容
});
// 页面加载完成后执行的操作
window.addEventListener("load", function () {
// 在这里可以执行页面加载完成后的操作
// 例如:初始化页面、获取初始数据等
});
// 修改按钮点击事件
var editButtons = document.querySelectorAll(".edit-button");
editButtons.forEach(function (button) {
button.addEventListener("click", function () {
var productId = button.getAttribute("data-product-id");
modalTitle.textContent = "修改商品";
productIdField.value = productId;
// 根据商品ID获取其他商品信息并填充到表单中
// 可以通过 AJAX 请求获取商品信息
// 然后将商品信息填充到表单字段中
modal.style.display = "block";
});
});
// 删除按钮点击事件
var deleteButtons = document.querySelectorAll(".delete-button");
deleteButtons.forEach(function (button) {
button.addEventListener("click", function () {
var productId = button.getAttribute("data-product-id");
// 根据商品ID执行删除商品操作
// 可以通过 AJAX 请求将商品ID发送到后端进行删除
// 然后可以根据返回的结果刷新商品列表或进行其他操作
});
});
// 添加/编辑商品表单提交
form.addEventListener("submit", function (event) {
event.preventDefault();
var productId = productIdField.value;
// 在这里可以通过 JavaScript 获取表单字段的值,进行保存等操作
// 例如:通过 AJAX 请求将表单数据发送到后端进行保存
// 然后可以根据返回的结果刷新商品列表或进行其他操作
modal.style.display = "none";
});
// 取消按钮点击事件
var cancelButton = document.querySelector(".cancel-button");
cancelButton.addEventListener("click", function () {
modal.style.display = "none";
});
$(document).ready(function() {
// 添加商品按钮点击事件
$('#add-product-btn').click(function() {
// 显示弹窗
$('#product-modal').show();
$('.overlay').show();
$('#modal-title').text('添加商品');
});
// 关闭弹窗按钮点击事件
$('.close').click(function() {
// 隐藏弹窗
$('#product-modal').hide();
$('.overlay').hide();
});
// 取消按钮点击事件
$('.cancel-button').click(function() {
// 隐藏弹窗
$('#product-modal').hide();
$('.overlay').hide();
});
// 保存按钮点击事件
$('.save-button').click(function(e) {
e.preventDefault();
// 获取表单数据
var productname = $('#productname').val();
var balance = $('#balance').val();
var vip = $('#vip').is(':checked');
// 发送POST请求到添加商品的URL
$.ajax({
url: '/add_product/',
type: 'POST',
data: {
'productname': productname,
'balance': balance,
'vip': vip
},
success: function(response) {
// 添加商品成功后的处理逻辑
// 隐藏弹窗
$('#product-modal').hide();
$('.overlay').hide();
// 清空表单数据
$('#productname').val('');
$('#balance').val('');
$('#vip').prop('checked', false);
// 刷新商品列表
refreshproductTable();
},
error: function(xhr, errmsg, err) {
// 处理错误情况
console.log(errmsg);
}
});
});
// 刷新按钮点击事件
$('#refresh-button').click(function() {
// 刷新商品列表
refreshproductTable();
});
// 刷新商品列表函数
function refreshproductTable() {
// 发送GET请求到刷新商品列表的URL
$.ajax({
url: '/refresh_products/',
type: 'GET',
success: function(response) {
// 更新商品列表
var products = response.products;
var tableBody = $('#product-table tbody');
tableBody.empty();
for (var i = 0; i < products.length; i++) {
var product = products[i];
var row = '<tr>' +
'<td>' + product.productname + '</td>' +
'<td>' + product.balance + '</td>' +
'<td>' + (product.vip ? '是' : '否') + '</td>' +
'</tr>';
tableBody.append(row);
}
},
error: function(xhr, errmsg, err) {
// 处理错误情况
console.log(errmsg);
}
});
}
// 页面加载时刷新商品列表
refreshproductTable();
});
</script>
{% endblock %}

@ -0,0 +1,372 @@
<!-- user_management.html -->
{% extends 'back/base.html' %}
{% block content %}
<style>
/* 页面样式 */
body {
font-family: Arial, sans-serif;
}
h2 {
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
#add-user-btn,
#refresh-button {
padding: 10px 20px;
margin-bottom: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.modal {
display: none;
position: fixed;
z-index: 999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 400px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
.close {
color: #888;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#user-form label {
display: block;
margin-top: 10px;
}
#user-form input[type="text"],
#user-form input[type="number"],
#user-form input[type="checkbox"] {
width: 100%;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.modal-buttons {
margin-top: 20px;
text-align: right;
}
.modal-buttons button {
margin-left: 10px;
}
/* 其他样式 */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
z-index: 999;
}
</style>
<h2>用户管理</h2>
<button id="add-user-btn">添加用户</button>
<button id="refresh-button">刷新</button>
<table id="user-table">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>余额</th>
<th>VIP</th>
<th>人脸ID</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{# {% for user_profile in user_profiles %}#}
{# <tr>#}
{# <td>{{ user_profile.user.id }}</td>#}
{# <td>{{ user_profile.user.username }}</td>#}
{# <td>{{ user_profile.balance }}</td>#}
{# <td>{% if user_profile.is_vip %}是{% else %}否{% endif %}</td>#}
{# <td>{{ user_profile.face_id }}</td>#}
{# <td>#}
{# <button class="edit-button" data-user-id="{{ user_profile.user.id }}">修改</button>#}
{# <button class="delete-button" data-user-id="{{ user_profile.user.id }}">删除</button>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
<tr>
<td>1</td>
<td>张三</td>
<td>100</td>
<td></td>
<td>1</td>
<td>
<button class="edit-button" data-user-id="1">修改</button>
<button class="delete-button" data-user-id="1">删除</button>
</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>200</td>
<td></td>
<td>2</td>
<td>
<button class="edit-button" data-user-id="2">修改</button>
<button class="delete-button" data-user-id="2">删除</button>
</td>
</tr>
</tbody>
</table>
<!-- 弹窗 -->
<div id="user-modal" class="modal">
<div class="modal-content">
<span class="close">&times;</span>
<h3 id="modal-title">添加用户</h3>
<form id="user-form">
<!-- 用户信息表单字段 -->
<input type="hidden" id="user-id" name="user-id">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required>
<label for="balance">余额:</label>
<input type="number" id="balance" name="balance" required>
<label for="vip">VIP:</label>
<input type="checkbox" id="vip" name="vip">
<!-- 保存和取消按钮 -->
<div class="modal-buttons">
<button type="submit" class="save-button">保存</button>
<button type="button" class="cancel-button">取消</button>
</div>
</form>
</div>
</div>
<script>
// 弹窗显示和隐藏
var modal = document.getElementById("user-modal");
var btn = document.getElementById("add-user-btn");
var span = document.getElementsByClassName("close")[0];
var form = document.getElementById("user-form");
var modalTitle = document.getElementById("modal-title");
var userIdField = document.getElementById("user-id");
btn.onclick = function () {
modalTitle.textContent = "添加用户";
form.reset();
modal.style.display = "block";
}
span.onclick = function () {
modal.style.display = "none";
}
window.onclick = function (event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
// 刷新按钮点击事件
var refreshButton = document.getElementById("refresh-button");
refreshButton.addEventListener("click", function () {
// 在这里可以执行获取最新内容的操作
// 例如:通过 AJAX 请求获取最新的用户列表数据并刷新表格内容
});
// 页面加载完成后执行的操作
window.addEventListener("load", function () {
// 在这里可以执行页面加载完成后的操作
// 例如:初始化页面、获取初始数据等
});
// 修改按钮点击事件
var editButtons = document.querySelectorAll(".edit-button");
editButtons.forEach(function (button) {
button.addEventListener("click", function () {
var userId = button.getAttribute("data-user-id");
modalTitle.textContent = "修改用户";
userIdField.value = userId;
// 根据用户ID获取其他用户信息并填充到表单中
// 可以通过 AJAX 请求获取用户信息
// 然后将用户信息填充到表单字段中
modal.style.display = "block";
});
});
// 删除按钮点击事件
var deleteButtons = document.querySelectorAll(".delete-button");
deleteButtons.forEach(function (button) {
button.addEventListener("click", function () {
var userId = button.getAttribute("data-user-id");
// 根据用户ID执行删除用户操作
// 可以通过 AJAX 请求将用户ID发送到后端进行删除
// 然后可以根据返回的结果刷新用户列表或进行其他操作
});
});
// 添加/编辑用户表单提交
form.addEventListener("submit", function (event) {
event.preventDefault();
var userId = userIdField.value;
// 在这里可以通过 JavaScript 获取表单字段的值,进行保存等操作
// 例如:通过 AJAX 请求将表单数据发送到后端进行保存
// 然后可以根据返回的结果刷新用户列表或进行其他操作
modal.style.display = "none";
});
// 取消按钮点击事件
var cancelButton = document.querySelector(".cancel-button");
cancelButton.addEventListener("click", function () {
modal.style.display = "none";
});
$(document).ready(function() {
// 添加用户按钮点击事件
$('#add-user-btn').click(function() {
// 显示弹窗
$('#user-modal').show();
$('.overlay').show();
$('#modal-title').text('添加用户');
});
// 关闭弹窗按钮点击事件
$('.close').click(function() {
// 隐藏弹窗
$('#user-modal').hide();
$('.overlay').hide();
});
// 取消按钮点击事件
$('.cancel-button').click(function() {
// 隐藏弹窗
$('#user-modal').hide();
$('.overlay').hide();
});
// 保存按钮点击事件
$('.save-button').click(function(e) {
e.preventDefault();
// 获取表单数据
var username = $('#username').val();
var balance = $('#balance').val();
var vip = $('#vip').is(':checked');
// 发送POST请求到添加用户的URL
$.ajax({
url: '/add_user/',
type: 'POST',
data: {
'username': username,
'balance': balance,
'vip': vip
},
success: function(response) {
// 添加用户成功后的处理逻辑
// 隐藏弹窗
$('#user-modal').hide();
$('.overlay').hide();
// 清空表单数据
$('#username').val('');
$('#balance').val('');
$('#vip').prop('checked', false);
// 刷新用户列表
refreshUserTable();
},
error: function(xhr, errmsg, err) {
// 处理错误情况
console.log(errmsg);
}
});
});
// 刷新按钮点击事件
$('#refresh-button').click(function() {
// 刷新用户列表
refreshUserTable();
});
// 刷新用户列表函数
function refreshUserTable() {
// 发送GET请求到刷新用户列表的URL
$.ajax({
url: '/refresh_users/',
type: 'GET',
success: function(response) {
// 更新用户列表
var users = response.users;
var tableBody = $('#user-table tbody');
tableBody.empty();
for (var i = 0; i < users.length; i++) {
var user = users[i];
var row = '<tr>' +
'<td>' + user.username + '</td>' +
'<td>' + user.balance + '</td>' +
'<td>' + (user.vip ? '是' : '否') + '</td>' +
'</tr>';
tableBody.append(row);
}
},
error: function(xhr, errmsg, err) {
// 处理错误情况
console.log(errmsg);
}
});
}
// 页面加载时刷新用户列表
refreshUserTable();
});
</script>
{% endblock %}

@ -0,0 +1,232 @@
/************************************************************
** CSS **
************************************************************/
html {
font-size: 16px;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
'Droid Sans', 'Helvetica Neue', 'Microsoft Yahei', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 100vw;
height: 100vh;
}
body * {
box-sizing: border-box;
flex-shrink: 0;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-col {
display: flex;
flex-direction: column;
}
.justify-start {
justify-content: flex-start;
}
.justify-between {
justify-content: space-between;
}
.items-center {
align-items: center;
}
.self-center {
align-self: center;
}
/** 清理默认样式 **/
a {
color: unset;
text-decoration: unset;
}
button {
padding: unset;
border-style: unset;
background-color: unset;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: unset;
font-size: unset;
font-weight: unset;
}
input,
textarea {
padding: unset;
outline: unset;
border-style: unset;
background-color: unset;
resize: unset;
}
p {
margin: unset;
}
select {
outline: unset;
border-style: unset;
}
table {
border-spacing: unset;
}
ul,
ol {
margin: unset;
padding: unset;
list-style-type: none;
}
.page {
padding: 25px 14px 30px 17px;
background-image: linear-gradient(90deg, #e7e5c300 35.9%, #e6dfdc 64.1%);
width: 100%;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.space-y-26 > *:not(:first-child) {
margin-top: 26px;
}
.section {
padding: 22px 21px 22px 25px;
background-color: #43cf7ccc;
border-radius: 15px;
}
.space-x-24 > *:not(:first-child) {
margin-left: 24px;
}
.logo-img {
width: 157px;
height: 157px;
}
.space-y-16 > *:not(:first-child) {
margin-top: 16px;
}
.text {
color: #ffffff;
font-size: 72px;
font-family: SourceHanSansCN;
font-weight: 700;
line-height: 68.5px;
}
.text_3 {
color: #ffffff;
font-size: 40px;
font-family: HarmonyOSSansSC;
font-weight: 700;
line-height: 31px;
letter-spacing: 2px;
}
.text-wrapper {
padding: 32px 0 34px;
background-color: #00baad8a;
border-radius: 10px;
height: 139px;
}
.text_2 {
margin-left: 26px;
margin-right: 20px;
color: #ffffff;
font-size: 80px;
font-family: AlimamaShuHeiTi;
line-height: 74px;
}
.text-wrapper_2 {
padding: 28px 0 24px;
background-color: #00baad8a;
border-radius: 15px;
}
.font_1 {
font-size: 45px;
font-family: SourceHanSansCN;
font-weight: 800;
color: #ffffff;
}
.text_4 {
line-height: 43.5px;
}
.section_2 {
padding: 93px 134px 148px;
background-image: linear-gradient(225.1deg, #6d819c 21.1%, #55967e 79.8%);
border-radius: 15px;
}
.image_2 {
width: 480px;
height: 360px;
}
.text-wrapper_3 {
margin-top: 83px;
padding: 28px 0 22px;
background-color: #cccccca6;
border-radius: 15px;
}
.text_5 {
line-height: 46.5px;
letter-spacing: 1.5px;
}
.text-wrapper_4 {
align-self: center;
margin-top: 79px;
}
.view {
padding: 42px 0 40px;
background-color: #43cf7c99;
border-radius: 15px;
width: 399px;
}
.footer-img {
border-radius: 15px;
/* width: 1048px;
height: 492px;
margin: auto; */
max-width: 100%;
height: auto;
}
.button {
color: #ffffff;
font-size: 60px;
font-family: SourceHanSansCN;
font-weight: 800;
line-height: 58px;
letter-spacing: 2px;
cursor: pointer;
}
.button:hover {
background-color: #43cf7bdf;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}

@ -0,0 +1,258 @@
/************************************************************
** CSS **
************************************************************/
html {
font-size: 16px;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
'Droid Sans', 'Helvetica Neue', 'Microsoft Yahei', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 100vw;
height: 100vh;
}
body * {
box-sizing: border-box;
flex-shrink: 0;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-col {
display: flex;
flex-direction: column;
}
.justify-start {
justify-content: flex-start;
}
.justify-between {
justify-content: space-between;
}
.items-center {
align-items: center;
}
.self-center {
align-self: center;
}
/** 清理默认样式 **/
a {
color: unset;
text-decoration: unset;
}
button {
padding: unset;
border-style: unset;
background-color: unset;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: unset;
font-size: unset;
font-weight: unset;
}
input,
textarea {
padding: unset;
outline: unset;
border-style: unset;
background-color: unset;
resize: unset;
}
p {
margin: unset;
}
select {
outline: unset;
border-style: unset;
}
table {
border-spacing: unset;
}
ul,
ol {
margin: unset;
padding: unset;
list-style-type: none;
}
.page {
padding: 25px 14px 29px 18px;
background-image: linear-gradient(90deg, #e7e5c300 35.9%, #e6dfdc 64.1%);
width: 100%;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.space-y-26 > *:not(:first-child) {
margin-top: 26px;
}
.section {
padding: 22px 21px 22px 25px;
background-color: #43cf7ccc;
border-radius: 15px;
}
.space-x-24 > *:not(:first-child) {
margin-left: 24px;
}
.logo-img {
width: 157px;
height: 157px;
}
.space-y-16 > *:not(:first-child) {
margin-top: 16px;
}
.text {
color: #ffffff;
font-size: 72px;
font-family: SourceHanSansCN;
font-weight: 700;
line-height: 68.5px;
}
.text_3 {
color: #ffffff;
font-size: 40px;
font-family: HarmonyOSSansSC;
font-weight: 700;
line-height: 31px;
letter-spacing: 2px;
}
.text-wrapper {
padding: 42px 0 34px;
background-color: #00baad8a;
border-radius: 10px;
height: 139px;
}
.text_2 {
margin-left: 40px;
margin-right: 28px;
color: #ffffff;
font-size: 80px;
font-family: AlimamaShuHeiTi;
line-height: 62.5px;
}
.text-wrapper_2 {
padding: 28px 0 24px;
background-color: #00baad8a;
border-radius: 15px;
}
.text_4 {
color: #ffffff;
font-size: 45px;
font-family: SourceHanSansCN;
font-weight: 800;
line-height: 43.5px;
}
.section_2 {
padding: 42px 0 42px;
background-image: linear-gradient(221.3deg, #6d819c 21.2%, #55967e 80%);
border-radius: 15px;
}
.list {
margin-left: 28px;
margin-right: 30px;
margin-top: -40px; /* 用魔法对抗魔法 */
}
.space-x-36 > *:not(:first-child) {
margin-left: 36px;
}
.font_1 {
font-size: 66px;
font-family: SourceHanSansCN;
letter-spacing: 2px;
line-height: 63px;
font-weight: 800;
color: #ffffff;
}
.font_2 {
font-size: 66px;
font-family: SourceHanSansCN;
letter-spacing: 2px;
line-height: 51px;
font-weight: 800;
color: #b04831cc;
}
.price {
margin-left: auto;
margin-right: 10px;
}
.section_3 {
margin-top: 46px;
}
.space-y-20 > *:not(:first-child) {
margin-top: 20px;
}
.view {
margin-left: 64px;
}
.space-x-58 > *:not(:first-child) {
margin-left: 58px;
}
.section_4 {
padding: 41px 0 33px;
background-color: #3b8686;
border-radius: 15px;
}
.text-wrapper_3 {
padding: 30px 0 24px;
background-color: #cccccc78;
border-radius: 20px;
width: 508px;
}
.sumPrice {
color: #b04831d9;
}
.text-wrapper_4 {
margin-top: 33px;
}
.view_2 {
padding: 44px 0 38px;
background-color: #43cf7c99;
border-radius: 15px;
width: 399px;
}
.button {
color: #ffffff;
font-size: 60px;
font-family: SourceHanSansCN;
font-weight: 800;
line-height: 57px;
letter-spacing: 2px;
cursor: pointer;
}
.button:hover {
background-color: #43cf7bdf;
}
/* 设置商品列表容器高度,使其可以滚动 */
.list {
height: 1100px; /* 设置合适的高度 */
overflow-y: scroll;
}

@ -0,0 +1,264 @@
/************************************************************
** CSS **
************************************************************/
html {
font-size: 16px;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
'Droid Sans', 'Helvetica Neue', 'Microsoft Yahei', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 100vw;
height: 100vh;
}
body * {
box-sizing: border-box;
flex-shrink: 0;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-col {
display: flex;
flex-direction: column;
}
.justify-start {
justify-content: flex-start;
}
.justify-between {
justify-content: space-between;
}
.items-center {
align-items: center;
}
.self-center {
align-self: center;
}
/** 清理默认样式 **/
a {
color: unset;
text-decoration: unset;
}
button {
padding: unset;
border-style: unset;
background-color: unset;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: unset;
font-size: unset;
font-weight: unset;
}
input,
textarea {
padding: unset;
outline: unset;
border-style: unset;
background-color: unset;
resize: unset;
}
p {
margin: unset;
}
select {
outline: unset;
border-style: unset;
}
table {
border-spacing: unset;
}
ul,
ol {
margin: unset;
padding: unset;
list-style-type: none;
}
.page {
padding: 25px 14px 30px 17px;
background-image: linear-gradient(90deg, #e7e5c300 35.9%, #e6dfdc 64.1%);
width: 100%;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
}
.space-y-26 > *:not(:first-child) {
margin-top: 26px;
}
.section {
padding: 22px 21px 22px 25px;
background-color: #43cf7ccc;
border-radius: 15px;
}
.space-x-24 > *:not(:first-child) {
margin-left: 24px;
}
.logo-img {
width: 157px;
height: 157px;
}
.space-y-16 > *:not(:first-child) {
margin-top: 16px;
}
.text {
color: #ffffff;
font-size: 72px;
font-family: SourceHanSansCN;
font-weight: 700;
line-height: 68.5px;
}
.text_3 {
color: #ffffff;
font-size: 40px;
font-family: SourceHanSansCN;
font-weight: 700;
line-height: 31px;
letter-spacing: 2px;
}
.text-wrapper {
padding: 32px 0 34px;
background-color: #00baad8a;
border-radius: 10px;
height: 139px;
}
.text_2 {
margin-left: 26px;
margin-right: 20px;
color: #ffffff;
font-size: 80px;
font-family: AlimamaShuHeiTi;
line-height: 74px;
}
.text-wrapper_2 {
padding: 28px 0 22px;
background-color: #00baad8a;
border-radius: 15px;
}
.font_1 {
font-size: 45px;
font-family: SourceHanSansCN;
letter-spacing: 2px;
line-height: 52px;
font-weight: 800;
color: #ffffff;
}
.text_4 {
line-height: 46px;
letter-spacing: unset;
}
.section_2 {
padding: 72px 248px 60px;
background-image: linear-gradient(225.1deg, #6d819c 21.1%, #55967e 79.8%);
border-radius: 15px;
}
.text_5 {
line-height: 51.5px;
}
.view_1 {
margin-right: 3px;
margin-top: 26px;
}
.text_6 {
margin-top: 40px;
}
.view {
margin-right: 4px;
margin-top: 26px;
}
.section_3 {
background-color: #cccccca6;
border-radius: 15px;
height: 96px;
}
.text_7 {
margin-top: 40px;
}
.text-wrapper_3 {
align-self: center;
margin-top: 54px;
}
.view_3 {
padding: 44px 0 38px;
background-color: #43cf7c99;
border-radius: 15px;
width: 315px;
}
.text_9 {
align-self: center;
margin-top: 36px;
color: #e5e5e5;
font-size: 36px;
font-family: SourceHanSansCN;
font-weight: 800;
line-height: 34.5px;
letter-spacing: 2px;
}
.text_9:hover {
color: #e5e5e597;
}
.footer-img {
border-radius: 15px;
/* width: 1048px;
height: 492px;
margin: auto; */
max-width: 100%;
height: auto;
}
.input {
padding: 10px 10px 10px 10px;
color: #ffffff;
font-size: 30px;
text-align: center;
}
.button {
color: #ffffff;
font-size: 60px;
font-family: SourceHanSansCN;
font-weight: 800;
line-height: 57.5px;
letter-spacing: 2px;
cursor: pointer;
}
.button:hover {
background-color: #43cf7bdf;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}

@ -0,0 +1,112 @@
.welcome{
text-align: center;
/* 文字上下居中 */
line-height: 20vh;
/* font-size: 50px; */
color: #fff;
background-color: rgb(7, 193, 96);
/* 字体大小 */
font-size: 80px;
height: 20vh;
margin: 0 auto;
}
main.photo{
/* 居中 */
margin: 0 auto;
}
main {
/* 对齐方式 */
text-align: center;
/* 字体大小 */
font-size: 40px;
/* 字体颜色 */
color: rgb(79, 61, 61);
/* 背景颜色 */
background-color: rgb(202, 249, 224);
/* 背景颜色无限延申 */
background-repeat: repeat;
/* 紧挨上文 */
margin: 0 auto;
}
footer {
/* 对齐方式 */
text-align: center;
/* 字体大小 */
font-size: 40px;
/* 字体颜色 */
color: rgb(79, 61, 61);
/* 背景颜色 */
background-color: rgb(202, 249, 224);
margin: 0 auto;
}
button{
/* 字体大小 */
font-size: 30px;
/* 字体颜色 */
color: #7E7E7E;
/* 背景颜色 */
background-color: rgb(202, 249, 224);
/* 居中 */
text-align: center;
/* 边框 */
/* 圆角 */
border-radius: 10px;
/* 边框比内部文字大一点 */
padding: 10px 20px;
}
button:hover{
background-color: grey;
color: #fff;
}
button:active{
background-color: rgb(20, 28, 20);
color: #fff;
}
.TextFace{
color: #7E7E7E;
margin-top: 20vh;
font-size: 60px;
}
*{
box-sizing: border-box;
background-color: rgb(202, 249, 224);
}
.reg{
/* 位于页面底部距离底部5vh,左右居中 */
position: fixed;
bottom: 3vh;
left: 50%;
transform: translateX(-50%);
/* 字体大小 */
font-size: 40px;
}
.photo{
/* 上下居中 */
/* 放大 */
transform: scale(1.5);
/* 下移10vh */
margin: 15vh auto 0;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
}

@ -0,0 +1,51 @@
.welcome{
text-align: center;
/* 文字上下居中 */
line-height: 20vh;
/* font-size: 50px; */
color: #fff;
background-color: rgb(7, 193, 96);
/* 字体大小 */
font-size: 80px;
height: 20vh;
margin: 0 auto;
}
.form{
font-size: 40px;
margin: 20px;
}
input{
font-size: 40px;
/* 圆角 */
border-radius: 10px;
height: 5vh;
margin: 1vh;
}
*{
box-sizing: border-box;
background-color: rgb(202, 249, 224);
}
.submit{
/* 位于页面底部距离底部5vh,左右居中 */
position: fixed;
bottom: 3vh;
left: 50%;
transform: translateX(-50%);
/* 字体大小 */
font-size: 50px;
/* 字体颜色 */
color: #7E7E7E;
/* 背景颜色 */
background-color: rgb(202, 249, 224);
/* 居中 */
text-align: center;
/* 边框 */
/* 圆角 */
border-radius: 10px;
/* 边框比内部文字大一点 */
padding: 10px 20px;
}

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>欢迎使用 - 无人超市</title>
<link rel="stylesheet" href="../static/css/logIn.css"/>
</head>
<body>
<div class="flex-col page space-y-26">
<div class="flex-row justify-between items-center section">
<div class="flex-row items-center space-x-24">
<img class="logo-img" src="../static/img/logo.png"/>
<div class="flex-col items-center space-y-16">
<span class="text">无人超市</span>
<span class="text_3">Smart Market</span>
</div>
</div>
<div class="flex-col justify-start text-wrapper"><span class="text_2">用户登录</span></div>
</div>
<div class="flex-col justify-start items-center text-wrapper_2">
<span class="font_1 text_4">欢迎使用无人超市</span>
</div>
<div class="flex-col section_2">
<img
class="self-center image_2"
src="../static/img/face-unscreen.gif"
/>
<div class="flex-col justify-start items-center text-wrapper_3">
<span class="font_1 text_5">请靠近机器,以进行人脸识别</span>
</div>
<button class="flex-col justify-start items-center text-wrapper_4 view button"
onclick="location.href=('../sign')">新用户注册
</button>
</div>
<img class="footer-img" src="../static/img/7x24.png"/>
</div>
</body>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// JavaScript代码显示和隐藏蒙版
$(document).ready(function () {
// 发送GET请求到API
$.get('/rec/', function (data) {
if (data.error) {
alert('API请求失败');
} else {
$('.text_5').text('欢迎,' + data.username);
//三秒后跳转到/cart/
setTimeout(function () {
window.location.href = "/cart/?username=" + data.username;
$.get('/cleanrfid/', function (data) {
if (data.error) {
alert('API请求失败');
}
});
}, 3000);
}
});
});
</script>
</html>

@ -0,0 +1,225 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>购物车 - 无人超市</title>
<link rel="stylesheet" href="../static/css/shoppingCart.css"/>
</head>
<body>
<div class="flex-col page space-y-26">
<div class="flex-row justify-between items-center section">
<div class="flex-row items-center space-x-24">
<img class="logo-img" src="../static/img/logo.png"/>
<div class="flex-col items-center space-y-16">
<span class="text">无人超市</span>
<span class="text_3">Smart Market</span>
</div>
</div>
<div class="flex-col justify-start text-wrapper"><span class="text_2 username">DustinZ</span></div>
</div>
<div class="flex-col justify-start items-center text-wrapper_2">
<span class="text_4" id="cartItemCount">购物车0件商品</span>
</div>
<div class="flex-col justify-start section_2">
<div class="flex-col list">
{# <!-- 商品 1 开始 -->#}
{# <div class="flex-row items-center list-item section_3 space-x-58">#}
{# <div class="flex-row items-center flex-auto space-x-36">#}
{# <img class="shrink-0 item_img" src="../static/img/item1.png"/>#}
{# <div class="flex-col items-start flex-auto space-y-20">#}
{# <span class="font_1 prodName">旺仔小馒头</span>#}
{# <span class="font_3 intro">好吃,爱吃!</span>#}
{# </div>#}
{# </div>#}
{# <div class="flex-row items-center group">#}
{# <span class="font_2 price">¥2.33</span>#}
{# </div>#}
{# </div>#}
{# <!-- 商品 2 开始 -->#}
{# <div class="flex-row items-center list-item section_3 space-x-58">#}
{# <div class="flex-row items-center flex-auto space-x-36">#}
{# <img class="shrink-0 item_img" src="../static/img/item2.png"/>#}
{# <div class="flex-col items-start flex-auto space-y-20">#}
{# <span class="font_1 prodName">旺仔牛奶</span>#}
{# <span class="font_3 intro">三年六班李子明推荐</span>#}
{# </div>#}
{# </div>#}
{# <div class="flex-row items-center group">#}
{# <span class="font_2 price">¥4.66</span>#}
{# </div>#}
{# </div>#}
{# <!-- 商品 3 开始 -->#}
{# <div class="flex-row items-center list-item section_3 space-x-58">#}
{# <div class="flex-row items-center flex-auto space-x-36">#}
{# <img class="shrink-0 item_img" src="../static/img/item3.png"/>#}
{# <div class="flex-col items-start flex-auto space-y-20">#}
{# <span class="font_1 prodName">牛奶糖</span>#}
{# <span class="font_3 intro">奶香浓郁,回味无穷</span>#}
{# </div>#}
{# </div>#}
{# <div class="flex-row items-center group">#}
{# <span class="font_2 price">¥3.80</span>#}
{# </div>#}
{# </div>#}
{# <!-- 商品 4 开始 -->#}
{# <div class="flex-row items-center list-item section_3 space-x-58">#}
{# <div class="flex-row items-center flex-auto space-x-36">#}
{# <img class="shrink-0 item_img" src="../static/img/item4.png"/>#}
{# <div class="flex-col items-start flex-auto space-y-20">#}
{# <span class="font_1 prodName">卫龙魔芋爽</span>#}
{# <span class="font_3 intro">爽滑轻弹,好吃不贵</span>#}
{# </div>#}
{# </div>#}
{# <div class="flex-row items-center group">#}
{# <span class="font_2 price">¥0.50</span>#}
{# </div>#}
{# </div>#}
{# <!-- 商品 4 结束 -->#}
</div>
</div>
<div class="flex-col items-center section_4">
<div class="flex-col justify-start items-center text-wrapper_3">
<span class="font_2 sumPrice" id="totalPrice">¥0.00</span>
</div>
<button class="flex-col justify-start items-center text-wrapper_4 view_2 button">确认支付</button>
</div>
</div>
</body>
</html>
<script>
// 计算并更新合计价格
function calculateTotalPrice() {
// 获取商品价格元素
var priceElements = document.getElementsByClassName("price");
var totalPrice = 0;
// 遍历所有价格元素,累加价格
for (var i = 0; i < priceElements.length; i++) {
var priceText = priceElements[i].innerText;
var price = parseFloat(priceText.substring(1)); // 去掉价格前面的人民币符号,并转换为浮点数
totalPrice += price;
}
// 更新合计价格元素
var totalPriceElement = document.getElementById("totalPrice");
totalPriceElement.innerText = "¥" + totalPrice.toFixed(2); // 保留两位小数
// 更新购物车件数
var cartItemCountElement = document.getElementById("cartItemCount");
var cartItemCount = priceElements.length;
cartItemCountElement.innerText = "购物车(" + cartItemCount + "件商品)";
// 将商品列表滚动到底部
var listElement = document.querySelector(".list");
listElement.scrollTop = listElement.scrollHeight;
// 如果需要,可以在这里执行其他操作,比如根据 totalPrice 的值做一些判断或其他计算
}
// 使用 MutationObserver 监听 DOM 变化
var observer = new MutationObserver(function () {
calculateTotalPrice();
});
// 监听购物车列表的变化
var listElement = document.querySelector(".list");
observer.observe(listElement, {childList: true, subtree: true});
// 初始化计算合计价格
calculateTotalPrice();
// 获取username参数的值
var username = new URLSearchParams(window.location.search).get("username");
// 查找具有class为username的元素
var usernameElements = document.getElementsByClassName("username");
// 遍历所有匹配的元素将其值修改为username参数的值
for (var i = 0; i < usernameElements.length; i++) {
usernameElements[i].textContent = username;
}
// 发送GET请求函数
function sendGetRequest(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
callback(xhr.responseText);
} else {
console.error('Error:', xhr.status);
}
}
};
xhr.open('GET', url, true);
xhr.send();
}
// 更新商品列表函数
function updateProductList() {
sendGetRequest('/updaterfid/', function (response) {
var data = JSON.parse(response);
var productList = data.product_list;
// 清空商品列表
var listContainer = document.querySelector('.list');
listContainer.innerHTML = '';
// 更新商品信息
productList.forEach(function (productID) {
var url = '/getProd?prodID=' + productID;
sendGetRequest(url, function (response) {
var productData = JSON.parse(response);
// 创建商品项
var listItem = document.createElement('div');
listItem.classList.add('flex-row', 'items-center', 'list-item', 'section_3', 'space-x-58');
// 创建商品图像
var itemImg = document.createElement('img');
itemImg.classList.add('shrink-0', 'item_img');
itemImg.src = '../static/img/item' + productData.prodID + '.png';
// 创建商品信息
var infoContainer = document.createElement('div');
infoContainer.classList.add('flex-col', 'items-start', 'flex-auto', 'space-y-20');
var prodName = document.createElement('span');
prodName.classList.add('font_1', 'prodName');
prodName.textContent = productData.prodName;
var intro = document.createElement('span');
intro.classList.add('font_3', 'intro');
intro.textContent = productData.intro;
infoContainer.appendChild(prodName);
infoContainer.appendChild(intro);
// 创建商品价格
var price = document.createElement('span');
price.classList.add('font_2', 'price');
price.textContent = '¥' + productData.prodPrice;
// 添加元素到商品项
listItem.appendChild(itemImg);
listItem.appendChild(infoContainer);
listItem.appendChild(price);
// 添加商品项到商品列表
listContainer.appendChild(listItem);
});
});
});
}
// 页面加载完成后执行更新商品列表
window.addEventListener('DOMContentLoaded', function () {
updateProductList();
});
// 每隔一段时间更新商品列表
setInterval(updateProductList, 8000); // 1000毫秒1秒
</script>

@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>用户注册 - 无人超市</title>
<link rel="stylesheet" href="../static/css/signUp.css"/>
</head>
<body>
<div class="flex-col page space-y-26">
<div class="flex-row justify-between items-center section">
<div class="flex-row items-center space-x-24">
<img class="logo-img" src="../static/img/logo.png">
<div class="flex-col items-center space-y-16">
<span class="text">无人超市</span>
<span class="text_3">Smart Market</span>
</div>
</div>
<div class="flex-col justify-start text-wrapper"><span class="text_2">用户注册</span></div>
</div>
<div class="flex-col justify-start items-center text-wrapper_2">
<span class="font_1 text_4">注册会员,开始享受便捷的购物体验吧!</span>
</div>
<form onsubmit="return false;">
<div class="flex-col section_2">
<span class="self-center font_1 text_5">用户名 | User Name</span>
<input class="view_1 section_3 input" name="用户名" maxlength="12" type="text" value=""
placeholder="请输入用户名"/>
<span class="self-center font_1 text_6">密码 | Password</span>
<input class="view section_3 input" name="密码" maxlength="16" type="password" placeholder="请输入密码"/>
<span class="self-center font_1 text_7">确认密码 | Confirm</span>
<input class="view_1 section_3 input" name="确认密码" maxlength="16" type="password"
placeholder="请再次输入密码"/>
<button class="flex-col justify-start items-center text-wrapper_3 view_3 button" name="提交"
onclick="onClick()">提交
</button>
<a class="text_9" href="../login">返回登录</a>
</div>
</form>
<img class="footer-img" src="../static/img/7x24.png"/>
</div>
<div class="overlay">
<div class="flex-col section_2">
<img
class="self-center image_2"
src="../static/img/face-unscreen.gif"
/>
<div class="flex-col justify-start items-center text-wrapper_3">
<span class="font_1 text_5">请靠近机器,以进行人脸识别</span>
</div>
</div>
</div>
</body>
</html>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$('.overlay').hide();
function onClick() {
$('.overlay').show();
var username = document.querySelector('input[name="用户名"]').value;
var postData = {
username: username
};
$.post('/reg/', postData, function (data) {
if (data.error) {
alert('API请求失败');
} else {
$('.text_5').text('欢迎,' + postData.username);
//三秒后跳转到/cart/
setTimeout(function () {
window.location.href = "/login";
}, 3000);
}
});
}
</script>

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎使用无人超市</title>
<link rel="stylesheet" href="../static/css/userLogin.css">
</head>
<main>
<h1 class="welcome">欢迎使用无人超市</h1>
<!-- <canvas id="gifFace" width="300" height="300"> </canvas> -->
<!-- <div><img src="smartshop/img/face.gif" alt="face"></div>
-->
<!-- 插入GIF图片--失败 -->
<div><img src="../static/img/face-unscreen.gif" alt="face" class="photo"></div>
<!-- <br> -->
<p class="TextFace">请靠近识别人脸</p>
<button type="button" class="reg">注册新用户</button>
<div class="overlay">
<p class="welcome-message">Loading...</p>
</div>
</main>
<script>
//点击button后跳转到注册页面
var reg = document.getElementsByClassName("reg")[0];
reg.onclick = function(){
window.location.href = "/sign/";
}
</script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// JavaScript代码显示和隐藏蒙版
$(document).ready(function () {
$('.overlay').hide(); // 隐藏蒙版
// 发送GET请求到API
$.get('/rec/', function (data) {
if (data.error) {
alert('API请求失败');
} else {
$('.overlay').show(); // 页面加载时显示蒙版
$('.welcome-message').text('欢迎,' + data.username);
//三秒后跳转到/cart/
setTimeout(function () {
window.location.href = "/cart/";
}, 3000);
}
});
});
</script>
</html>

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>欢迎使用无人超市</title>
<link rel="stylesheet" href="../static/css/userSign.css">
</head>
<main>
<h1 class="welcome">用户注册</h1>
<!-- <canvas id="gifFace" width="300" height="300"> </canvas> -->
<!-- <div><img src="smartshop/img/face.gif" alt="face"></div> -->
</main>
<br>
<form action="../static/js/userSign.js" method="POST" class="form">
<br>
<div style="text-align: center;">
<label>用户名</label>
<!-- name属性是必须的,用来提交给数据库 -->
<input type="text" name="用户名" placeholder="请输入用户名">
</div>
<br>
<div style="text-align: center;">
<label>密码</label>
<!-- name属性是必须的,用来提交给数据库 -->
<input type="password" name="密码" placeholder="请输入密码">
</div>
<br>
<div style="text-align: center;">
<label>确认密码</label>
<!-- name属性是必须的,用来提交给数据库 -->
<input type="password" name="确认密码" placeholder="请再次输入密码">
</div>
<br>
<!-- 居中 -->
<div style="text-align: center;"><input class="submit" type="submit" name="提交" value="提交"></div>
</form>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

@ -0,0 +1 @@
window.location.href = "/login/";
Loading…
Cancel
Save